@lovelybunch/api 1.0.75-alpha.4 → 1.0.75-alpha.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/dist/routes/api/v1/ai/index.js +0 -2
- package/dist/routes/api/v1/ai/route.js +105 -241
- package/dist/routes/api/v1/events/status/route.d.ts +1 -1
- package/dist/routes/api/v1/jobs/[id]/run/route.d.ts +2 -2
- package/dist/routes/api/v1/jobs/[id]/runs/[runId]/route.d.ts +2 -2
- package/dist/routes/api/v1/jobs/status/route.d.ts +1 -1
- package/dist/routes/api/v1/proposals/[id]/route.d.ts +8 -8
- package/package.json +6 -4
- package/static/assets/{ActivityPage-BI-4IFaP.js → ActivityPage-6xf2Jxp0.js} +1 -1
- package/static/assets/{AgentDetailPage-eVEOya9x.js → AgentDetailPage-1hbFBTeB.js} +1 -1
- package/static/assets/{AgentEditPage-Ds5XXaak.js → AgentEditPage-qMmg057j.js} +1 -1
- package/static/assets/{AgentsPage-CE59G63x.js → AgentsPage-DyyJrXqo.js} +2 -2
- package/static/assets/{AgentsSettingsPage-uVKYxuov.js → AgentsSettingsPage-Bf61k6i0.js} +2 -2
- package/static/assets/{ApiKeysSettingsPage-CTPK48rU.js → ApiKeysSettingsPage-DlWMBuQb.js} +2 -2
- package/static/assets/{ArchitectureEditPage-Cn4zVbPK.js → ArchitectureEditPage-C6MWFHCp.js} +1 -1
- package/static/assets/{ArchitecturePage-CCocwST0.js → ArchitecturePage-CxQtPG4d.js} +1 -1
- package/static/assets/{AuthSettingsPage-C-nDwiO4.js → AuthSettingsPage-w0blkw8Q.js} +2 -2
- package/static/assets/{CallbackPage-ZcrfbMj2.js → CallbackPage-ByjWTMuG.js} +1 -1
- package/static/assets/{CodePage-DuHcwCCu.js → CodePage-aWl0jKwx.js} +2 -2
- package/static/assets/{CollapsibleSection-DreaKHR1.js → CollapsibleSection-B1AU3exJ.js} +1 -1
- package/static/assets/{DashboardPage-Da0zfmye.js → DashboardPage-CAToLPqr.js} +2 -2
- package/static/assets/{GitPage-DE0oU3cj.js → GitPage-DGjEzIUs.js} +1 -1
- package/static/assets/{GitSettingsPage-DndQUnzg.js → GitSettingsPage-X1GEO1Ti.js} +2 -2
- package/static/assets/{IdentityPage-DD-9upeG.js → IdentityPage-L0foq6qN.js} +3 -3
- package/static/assets/{ImplementationStepsEditor-C3vh3Hc0.js → ImplementationStepsEditor-Dn88eiVP.js} +1 -1
- package/static/assets/IntegrationsSettingsPage-WX1lSaWr.js +1 -0
- package/static/assets/JobDetailPage-CvNs3cEP.js +1 -0
- package/static/assets/KnowledgeDetailPage-DXjmZdQl.js +1 -0
- package/static/assets/KnowledgeEditPage-C70yoVFM.js +1 -0
- package/static/assets/{KnowledgePage-cOsVzN4A.js → KnowledgePage-EUJ9c9By.js} +2 -2
- package/static/assets/{LoginPage-CvVZ8le4.js → LoginPage-Df_q-ACP.js} +1 -1
- package/static/assets/{McpSettingsPage-_q1tdgv0.js → McpSettingsPage-4b5M8tpH.js} +1 -1
- package/static/assets/{NewAgentPage-DIzdUSPb.js → NewAgentPage-BqvZZJmC.js} +1 -1
- package/static/assets/NewKnowledgePage-CqKz6_K-.js +9 -0
- package/static/assets/{NewProposalPage-h91-EksD.js → NewProposalPage-DR9UZich.js} +2 -2
- package/static/assets/{ProjectEditPage-CcwGPvlc.js → ProjectEditPage-5YxG7Xxd.js} +1 -1
- package/static/assets/ProjectPage-BBhGv2fS.js +1 -0
- package/static/assets/{PromptsSettingsPage-BTOf3Xzc.js → PromptsSettingsPage-DLrpZcDA.js} +1 -1
- package/static/assets/ProposalDetailPage-C4tagoNE.js +1 -0
- package/static/assets/ProposalEditPage-Bz-oEsLL.js +1 -0
- package/static/assets/{ProposalsPage-ekrWnqoo.js → ProposalsPage-BKRjNF4y.js} +1 -1
- package/static/assets/{ResourcesPage-90Wdfshd.js → ResourcesPage-BZrToY-V.js} +4 -4
- package/static/assets/{RoleEditPage-DY75XHIO.js → RoleEditPage-C2vWadxy.js} +1 -1
- package/static/assets/{RolePage-CXas69QY.js → RolePage-CE9y3rMd.js} +1 -1
- package/static/assets/{RulesSettingsPage-p6AjPCI0.js → RulesSettingsPage-BidnZaAT.js} +2 -2
- package/static/assets/SchedulePage-DU7ng6Gq.js +4 -0
- package/static/assets/SourceInput-CCa7okhU.js +1 -0
- package/static/assets/{TagInput-Dfue2spU.js → TagInput-Chn207ze.js} +1 -1
- package/static/assets/TerminalPage-CEYgdKT2.js +1 -0
- package/static/assets/{TerminalSessionPage-FueIeaIL.js → TerminalSessionPage-C8YA0AmM.js} +4 -4
- package/static/assets/{UserPreferencesPage-C9yXdIdZ.js → UserPreferencesPage-lPgr1ngr.js} +1 -1
- package/static/assets/{UserSettingsPage-ba7UUKyG.js → UserSettingsPage-ctHFqz6e.js} +1 -1
- package/static/assets/{UtilitiesPage-5Zot5Svs.js → UtilitiesPage-BVxyh0Ce.js} +1 -1
- package/static/assets/{alert-BhJUdRgG.js → alert-D5jzRTa5.js} +1 -1
- package/static/assets/{arrow-down-BYk0k85B.js → arrow-down-4I_8gyhd.js} +1 -1
- package/static/assets/{arrow-left-TQT21N4S.js → arrow-left-DZzHrGWA.js} +1 -1
- package/static/assets/{arrow-up-BkSi1XTr.js → arrow-up-B4VxSS3_.js} +1 -1
- package/static/assets/{badge-DS8SPg0q.js → badge-DvLOhob-.js} +1 -1
- package/static/assets/{browser-modal-CgvW-bbQ.js → browser-modal-DzaD2oDW.js} +2 -2
- package/static/assets/{calendar-AzmVUvxT.js → calendar-BNe2rz1T.js} +1 -1
- package/static/assets/{card-C4vq6AMz.js → card-BguljVtN.js} +1 -1
- package/static/assets/{chevron-left-CeRwwCqx.js → chevron-left-DZQ_tMvU.js} +1 -1
- package/static/assets/{chevrons-up-BdEukQhU.js → chevrons-up-BCenbxtV.js} +1 -1
- package/static/assets/{circle-alert-C1JRie1k.js → circle-alert-CZtpB74t.js} +1 -1
- package/static/assets/{circle-check-big-CQBGgL4s.js → circle-check-big-CTApxALS.js} +1 -1
- package/static/assets/{circle-check-DxiLNIIS.js → circle-check-hWIEYAMH.js} +1 -1
- package/static/assets/{circle-play-qq_sLPT0.js → circle-play-BF3gDlvZ.js} +1 -1
- package/static/assets/{circle-x-kpttvnBF.js → circle-x-BtYTEkcT.js} +1 -1
- package/static/assets/{clipboard-CBBHo2mi.js → clipboard-B8Tnfm3W.js} +1 -1
- package/static/assets/{clock-Ck6whvmg.js → clock-_sj3uVNp.js} +1 -1
- package/static/assets/{download-Cx4OcU33.js → download-CPGv4d5Q.js} +1 -1
- package/static/assets/external-link-CtxWkvSs.js +6 -0
- package/static/assets/{eye-2CnfcAd3.js → eye-_nXnan_b.js} +1 -1
- package/static/assets/{folder-git-2-CvwpDtwI.js → folder-git-2-C_Zkp5wq.js} +1 -1
- package/static/assets/index-BlLRLvWP.js +462 -0
- package/static/assets/index-DVTgTsDa.css +2 -0
- package/static/assets/{info-BO6_vv66.js → info-fJ-d5-p-.js} +1 -1
- package/static/assets/{label-B-1O5hdX.js → label-PINvlQb-.js} +1 -1
- package/static/assets/{markdown-editor-H-rT6Hat.js → markdown-editor-B7Zxgu1u.js} +1 -1
- package/static/assets/{pause-CW39bpDf.js → pause-C9zNWRax.js} +1 -1
- package/static/assets/{play-Bqd-yHZN.js → play-BpXD0Ub0.js} +1 -1
- package/static/assets/{plus-BWhZkuI2.js → plus-DBJTL6qk.js} +1 -1
- package/static/assets/{radio-group-CHbb2Tdt.js → radio-group-DBaY5DVP.js} +1 -1
- package/static/assets/{refresh-cw-CaOTs34G.js → refresh-cw-SQsUc3_C.js} +1 -1
- package/static/assets/{search-D2duvyuf.js → search-CBNlhD-8.js} +1 -1
- package/static/assets/{switch-BRsOxt7T.js → switch-C3ys7mIF.js} +1 -1
- package/static/assets/{tabs--rTULKlo.js → tabs-BpxOu6UL.js} +1 -1
- package/static/assets/{tag-BQ5pJD32.js → tag-Cu4oj34X.js} +1 -1
- package/static/assets/{terminal-preview-ewZC6O1I.js → terminal-preview-B5-BekLC.js} +1 -1
- package/static/assets/{use-terminal-Cya6EYny.js → use-terminal-CDMgbskg.js} +1 -1
- package/static/assets/{zap-DQNov92q.js → zap-LrtVPxxV.js} +1 -1
- package/static/index.html +2 -2
- package/static/assets/IntegrationsSettingsPage-B4J4wDXt.js +0 -1
- package/static/assets/JobDetailPage-tHRLIpQI.js +0 -1
- package/static/assets/KnowledgeDetailPage-Dh315TpW.js +0 -1
- package/static/assets/KnowledgeEditPage-B5bNMMvh.js +0 -1
- package/static/assets/NewKnowledgePage-weR174CB.js +0 -9
- package/static/assets/ProjectPage-D9APD9HG.js +0 -1
- package/static/assets/ProposalDetailPage-DbUTHokj.js +0 -1
- package/static/assets/ProposalEditPage-97pQXtDD.js +0 -1
- package/static/assets/SchedulePage-C-Yevtfw.js +0 -4
- package/static/assets/SourceInput-CLzuDG61.js +0 -1
- package/static/assets/TerminalPage-BbA46X-G.js +0 -1
- package/static/assets/index-C8_b70Ej.css +0 -2
- package/static/assets/index-Df8kpDhM.js +0 -468
|
@@ -4,6 +4,8 @@ import { existsSync, readFileSync, promises as fs, createReadStream } from 'fs';
|
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import readline from 'readline';
|
|
6
6
|
import { ZodError } from 'zod';
|
|
7
|
+
import { streamText, tool, jsonSchema, stepCountIs } from 'ai';
|
|
8
|
+
import { createAnthropic } from '@ai-sdk/anthropic';
|
|
7
9
|
import { getLogsDir, listProposals, getProposal, createProposal, updateProposal, deleteProposal, } from '@lovelybunch/core';
|
|
8
10
|
import { proposalsFullTool, knowledgeTool, normalizeKnowledgeMetadata, eventsTool, projectContextTool, architectureContextTool, roleContextTool } from '@lovelybunch/mcp';
|
|
9
11
|
import matter from 'gray-matter';
|
|
@@ -37,279 +39,141 @@ function getGlobalApiKey(provider) {
|
|
|
37
39
|
}
|
|
38
40
|
export async function POST(c) {
|
|
39
41
|
try {
|
|
40
|
-
const { message: userMessage, history,
|
|
42
|
+
const { message: userMessage, history, context, contextContent, agentPersona, systemPrompt: systemOverride, attachedContextFiles } = await c.req.json();
|
|
41
43
|
if (!userMessage) {
|
|
42
44
|
return c.json({ error: "Message is required" }, 400);
|
|
43
45
|
}
|
|
44
46
|
// Prefer global config key (set via CLI/UI), fallback to env var
|
|
45
|
-
|
|
46
|
-
if (!
|
|
47
|
+
const apiKey = getGlobalApiKey('anthropic') || process.env.ANTHROPIC_API_KEY;
|
|
48
|
+
if (!apiKey) {
|
|
47
49
|
return c.json({
|
|
48
|
-
error: "
|
|
49
|
-
hint: "Set via 'coconut config set-key -p
|
|
50
|
+
error: "Anthropic API key not configured",
|
|
51
|
+
hint: "Set via 'coconut config set-key -p anthropic -k <KEY>' (or 'nut config set-key -p anthropic -k <KEY>'), or set ANTHROPIC_API_KEY env var"
|
|
50
52
|
}, 500);
|
|
51
53
|
}
|
|
54
|
+
// Initialize Anthropic model via AI SDK
|
|
55
|
+
const anthropicClient = createAnthropic({ apiKey });
|
|
56
|
+
const model = anthropicClient('claude-sonnet-4-5-20250929');
|
|
52
57
|
const baseSystem = systemOverride || getSystemPrompt();
|
|
53
58
|
const systemPrompt = agentPersona
|
|
54
59
|
? `${baseSystem}\n\nThe following persona is authoritative and overrides general guidance above. You must strictly follow it.\n\n${agentPersona}`
|
|
55
60
|
: baseSystem;
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
{
|
|
72
|
-
type: "function",
|
|
73
|
-
function: projectContextTool
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
type: "function",
|
|
77
|
-
function: architectureContextTool
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
type: "function",
|
|
81
|
-
function: roleContextTool
|
|
61
|
+
// Build context messages from attached files
|
|
62
|
+
const contextMessages = [];
|
|
63
|
+
if (Array.isArray(attachedContextFiles)) {
|
|
64
|
+
for (const file of attachedContextFiles) {
|
|
65
|
+
if (file && typeof file.content === 'string' && file.content.trim().length > 0) {
|
|
66
|
+
contextMessages.push({
|
|
67
|
+
role: 'user',
|
|
68
|
+
content: `[ATTACHED CONTEXT - FULL CONTENT INCLUDED BELOW - DO NOT USE TOOLS TO FETCH THIS FILE]\nDocument: ${file.name || file.path || 'reference'}\nType: ${file.type || 'context'}\n\n--- BEGIN CONTENT ---\n${file.content}\n--- END CONTENT ---`
|
|
69
|
+
});
|
|
70
|
+
// Add a brief assistant acknowledgment so the conversation alternates correctly
|
|
71
|
+
contextMessages.push({
|
|
72
|
+
role: 'assistant',
|
|
73
|
+
content: `I've noted the attached context document "${file.name || 'reference'}". I'll reference it as needed.`
|
|
74
|
+
});
|
|
75
|
+
}
|
|
82
76
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
? attachedContextFiles
|
|
86
|
-
.filter((file) => file && typeof file.content === 'string' && file.content.trim().length > 0)
|
|
87
|
-
.map((file) => ({
|
|
88
|
-
role: 'system',
|
|
89
|
-
content: `[ATTACHED CONTEXT - FULL CONTENT INCLUDED BELOW - DO NOT USE TOOLS TO FETCH THIS FILE]\nDocument: ${file.name || file.path || 'reference'}\nType: ${file.type || 'context'}\n\n--- BEGIN CONTENT ---\n${file.content}\n--- END CONTENT ---`
|
|
90
|
-
}))
|
|
91
|
-
: [];
|
|
92
|
-
// Compose the message list: system + history (preferred) or single message
|
|
77
|
+
}
|
|
78
|
+
// Compose the message list: history (preferred) or single message
|
|
93
79
|
let messagesPayload;
|
|
94
80
|
if (Array.isArray(history) && history.length > 0) {
|
|
95
|
-
//
|
|
96
|
-
const sanitized = history.filter(m => m && (m.role === 'user' || m.role === 'assistant') && typeof m.content === 'string');
|
|
81
|
+
// Sanitize roles to user/assistant only, preserve order
|
|
82
|
+
const sanitized = history.filter((m) => m && (m.role === 'user' || m.role === 'assistant') && typeof m.content === 'string');
|
|
97
83
|
messagesPayload = [
|
|
98
|
-
{ role: 'system', content: systemPrompt },
|
|
99
84
|
...contextMessages,
|
|
100
85
|
...sanitized,
|
|
101
86
|
];
|
|
102
87
|
}
|
|
103
88
|
else {
|
|
104
89
|
messagesPayload = [
|
|
105
|
-
{ role: 'system', content: systemPrompt },
|
|
106
90
|
...contextMessages,
|
|
107
91
|
{ role: 'user', content: userMessage },
|
|
108
92
|
];
|
|
109
93
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
94
|
+
// Define tools with execute functions using AI SDK tool()
|
|
95
|
+
// Using tool<any, string>() to properly type jsonSchema-based tools
|
|
96
|
+
const storage = new FileStorageAdapter();
|
|
97
|
+
const aiTools = {
|
|
98
|
+
change_proposals: tool({
|
|
99
|
+
description: proposalsFullTool.description,
|
|
100
|
+
inputSchema: jsonSchema(proposalsFullTool.parameters),
|
|
101
|
+
execute: async (args) => {
|
|
102
|
+
const result = await executeProposalsToolDirect(args, storage);
|
|
103
|
+
return JSON.stringify(result);
|
|
104
|
+
},
|
|
105
|
+
}),
|
|
106
|
+
knowledge_documents: tool({
|
|
107
|
+
description: knowledgeTool.description,
|
|
108
|
+
inputSchema: jsonSchema(knowledgeTool.parameters),
|
|
109
|
+
execute: async (args) => {
|
|
110
|
+
const result = await executeKnowledgeToolDirect(args);
|
|
111
|
+
return JSON.stringify(result);
|
|
112
|
+
},
|
|
113
|
+
}),
|
|
114
|
+
activity_events: tool({
|
|
115
|
+
description: eventsTool.description,
|
|
116
|
+
inputSchema: jsonSchema(eventsTool.parameters),
|
|
117
|
+
execute: async (args) => {
|
|
118
|
+
const result = await executeEventsToolDirect(args);
|
|
119
|
+
return JSON.stringify(result);
|
|
120
|
+
},
|
|
121
|
+
}),
|
|
122
|
+
project_context: tool({
|
|
123
|
+
description: projectContextTool.description,
|
|
124
|
+
inputSchema: jsonSchema(projectContextTool.parameters),
|
|
125
|
+
execute: async (args) => {
|
|
126
|
+
const result = await executeProjectContextToolDirect(args);
|
|
127
|
+
return JSON.stringify(result);
|
|
128
|
+
},
|
|
129
|
+
}),
|
|
130
|
+
architecture_context: tool({
|
|
131
|
+
description: architectureContextTool.description,
|
|
132
|
+
inputSchema: jsonSchema(architectureContextTool.parameters),
|
|
133
|
+
execute: async (args) => {
|
|
134
|
+
const result = await executeArchitectureContextToolDirect(args);
|
|
135
|
+
return JSON.stringify(result);
|
|
136
|
+
},
|
|
137
|
+
}),
|
|
138
|
+
role_context: tool({
|
|
139
|
+
description: roleContextTool.description,
|
|
140
|
+
inputSchema: jsonSchema(roleContextTool.parameters),
|
|
141
|
+
execute: async (args) => {
|
|
142
|
+
const result = await executeRoleContextToolDirect(args);
|
|
143
|
+
return JSON.stringify(result);
|
|
144
|
+
},
|
|
145
|
+
}),
|
|
116
146
|
};
|
|
117
|
-
// Add tools if enabled
|
|
118
|
-
if (tools) {
|
|
119
|
-
requestBody.tools = tools;
|
|
120
|
-
requestBody.tool_choice = "auto";
|
|
121
|
-
}
|
|
122
147
|
// Debug logging
|
|
123
148
|
console.log('AI Request Debug:', {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
model: requestBody.model
|
|
149
|
+
toolCount: Object.keys(aiTools).length,
|
|
150
|
+
messageCount: messagesPayload.length,
|
|
151
|
+
model: 'claude-sonnet-4-5-20250929'
|
|
128
152
|
});
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
153
|
+
// Use AI SDK streamText - handles the entire LLM + tool loop automatically
|
|
154
|
+
const result = streamText({
|
|
155
|
+
model,
|
|
156
|
+
system: systemPrompt,
|
|
157
|
+
messages: messagesPayload,
|
|
158
|
+
tools: aiTools,
|
|
159
|
+
stopWhen: stepCountIs(5), // Max 5 tool-use rounds
|
|
160
|
+
temperature: 0.7,
|
|
161
|
+
maxOutputTokens: 8000,
|
|
138
162
|
});
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
statusText: response.statusText,
|
|
144
|
-
error: errorText,
|
|
145
|
-
model: requestBody.model
|
|
146
|
-
});
|
|
147
|
-
// Try to parse error for more detail
|
|
148
|
-
let errorDetail = "Failed to get AI response";
|
|
149
|
-
try {
|
|
150
|
-
const errorJson = JSON.parse(errorText);
|
|
151
|
-
errorDetail = errorJson.error?.message || errorJson.error || errorDetail;
|
|
152
|
-
}
|
|
153
|
-
catch {
|
|
154
|
-
// Use raw text if not JSON
|
|
155
|
-
if (errorText.length < 200) {
|
|
156
|
-
errorDetail = errorText || errorDetail;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
return c.json({ error: errorDetail, status: response.status }, response.status);
|
|
160
|
-
}
|
|
161
|
-
// Handle streaming response
|
|
162
|
-
if (stream === true && response.body) {
|
|
163
|
-
return c.newResponse(response.body, {
|
|
164
|
-
status: 200,
|
|
165
|
-
headers: {
|
|
166
|
-
'Content-Type': 'text/event-stream',
|
|
167
|
-
'Cache-Control': 'no-cache',
|
|
168
|
-
'Connection': 'keep-alive',
|
|
169
|
-
},
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
const data = await response.json();
|
|
173
|
-
const aiMessage = data.choices?.[0]?.message;
|
|
174
|
-
if (!aiMessage) {
|
|
175
|
-
console.error("No AI message in response:", {
|
|
176
|
-
model: requestBody.model,
|
|
177
|
-
choices: data.choices,
|
|
178
|
-
error: data.error
|
|
179
|
-
});
|
|
180
|
-
const errorDetail = data.error?.message || data.error || "No response from AI model";
|
|
181
|
-
return c.json({ error: errorDetail }, 500);
|
|
182
|
-
}
|
|
183
|
-
// Handle tool calls
|
|
184
|
-
if (aiMessage.tool_calls && aiMessage.tool_calls.length > 0) {
|
|
185
|
-
const toolResults = await executeToolCalls(aiMessage.tool_calls);
|
|
186
|
-
// Add tool results to the conversation and get final response
|
|
187
|
-
const messagesWithTools = [
|
|
188
|
-
...messagesPayload,
|
|
189
|
-
aiMessage,
|
|
190
|
-
...toolResults.map(result => ({
|
|
191
|
-
role: 'tool',
|
|
192
|
-
content: result.content,
|
|
193
|
-
tool_call_id: result.tool_call_id
|
|
194
|
-
}))
|
|
195
|
-
];
|
|
196
|
-
// Get final response from AI with tool results
|
|
197
|
-
// Use lower max_tokens for tool result synthesis (typically just needs to summarize)
|
|
198
|
-
const finalResponse = await fetch("https://openrouter.ai/api/v1/chat/completions", {
|
|
199
|
-
method: "POST",
|
|
200
|
-
headers: {
|
|
201
|
-
"Authorization": `Bearer ${openRouterKey}`,
|
|
202
|
-
"Content-Type": "application/json",
|
|
203
|
-
"HTTP-Referer": process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3001",
|
|
204
|
-
"X-Title": "Coconut AI Assistant",
|
|
205
|
-
},
|
|
206
|
-
body: JSON.stringify({
|
|
207
|
-
model: model || "openai/gpt-4o",
|
|
208
|
-
messages: messagesWithTools,
|
|
209
|
-
temperature: 0.5, // Lower temperature for more consistent tool result summaries
|
|
210
|
-
max_tokens: 2000, // Reduced from 8000 - tool summaries don't need to be as long
|
|
211
|
-
}),
|
|
212
|
-
});
|
|
213
|
-
if (!finalResponse.ok) {
|
|
214
|
-
const error = await finalResponse.text();
|
|
215
|
-
console.error("OpenRouter API error for final response:", error);
|
|
216
|
-
return c.json({ error: "Failed to get final AI response" }, 500);
|
|
217
|
-
}
|
|
218
|
-
const finalData = await finalResponse.json();
|
|
219
|
-
const finalMessage = finalData.choices?.[0]?.message;
|
|
220
|
-
return c.json({
|
|
221
|
-
response: finalMessage?.content || "Tool execution completed",
|
|
222
|
-
toolCalls: aiMessage.tool_calls,
|
|
223
|
-
toolResults: toolResults
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
return c.json({ response: aiMessage.content });
|
|
163
|
+
// Return a plain text stream response
|
|
164
|
+
// toTextStreamResponse() streams text-delta events as UTF-8 chunks,
|
|
165
|
+
// ignoring tool calls, tool results, and other non-text events
|
|
166
|
+
return result.toTextStreamResponse();
|
|
227
167
|
}
|
|
228
168
|
catch (error) {
|
|
229
169
|
console.error("AI API error:", error);
|
|
230
170
|
return c.json({ error: "Internal server error" }, 500);
|
|
231
171
|
}
|
|
232
172
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
try {
|
|
238
|
-
// Handle both function calling formats
|
|
239
|
-
const functionName = toolCall.function?.name || toolCall.name;
|
|
240
|
-
let functionArgs;
|
|
241
|
-
if (toolCall.function?.arguments) {
|
|
242
|
-
try {
|
|
243
|
-
// Try to sanitize common JSON issues before parsing
|
|
244
|
-
let argsStr = toolCall.function.arguments;
|
|
245
|
-
// Remove trailing commas before ] or }
|
|
246
|
-
argsStr = argsStr.replace(/,(\s*[}\]])/g, '$1');
|
|
247
|
-
// Fix common LLM JSON issues:
|
|
248
|
-
// Remove control characters (except \n, \r, \t which are valid in JSON strings)
|
|
249
|
-
argsStr = argsStr.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '');
|
|
250
|
-
functionArgs = JSON.parse(argsStr);
|
|
251
|
-
}
|
|
252
|
-
catch (parseError) {
|
|
253
|
-
// LLM may generate invalid JSON with unescaped characters in long content
|
|
254
|
-
const errorMsg = parseError instanceof Error ? parseError.message : 'Unknown parse error';
|
|
255
|
-
const hint = errorMsg.includes('position')
|
|
256
|
-
? 'The content may contain unescaped quotes or special characters. Try updating with shorter/simpler content, or update one field at a time.'
|
|
257
|
-
: 'Please retry with simpler content.';
|
|
258
|
-
return {
|
|
259
|
-
tool_call_id: toolCall.id,
|
|
260
|
-
content: JSON.stringify({
|
|
261
|
-
success: false,
|
|
262
|
-
error: `Invalid tool arguments: ${errorMsg}. ${hint}`
|
|
263
|
-
})
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
else {
|
|
268
|
-
functionArgs = toolCall.arguments;
|
|
269
|
-
}
|
|
270
|
-
let result = { success: false, error: 'Unknown tool' };
|
|
271
|
-
// Execute tools directly instead of making HTTP requests
|
|
272
|
-
if (functionName === 'change_proposals') {
|
|
273
|
-
result = await executeProposalsToolDirect(functionArgs, storage);
|
|
274
|
-
}
|
|
275
|
-
else if (functionName === 'knowledge_documents') {
|
|
276
|
-
result = await executeKnowledgeToolDirect(functionArgs);
|
|
277
|
-
}
|
|
278
|
-
else if (functionName === 'activity_events') {
|
|
279
|
-
result = await executeEventsToolDirect(functionArgs);
|
|
280
|
-
}
|
|
281
|
-
else if (functionName === 'project_context') {
|
|
282
|
-
result = await executeProjectContextToolDirect(functionArgs);
|
|
283
|
-
}
|
|
284
|
-
else if (functionName === 'architecture_context') {
|
|
285
|
-
result = await executeArchitectureContextToolDirect(functionArgs);
|
|
286
|
-
}
|
|
287
|
-
else if (functionName === 'role_context') {
|
|
288
|
-
result = await executeRoleContextToolDirect(functionArgs);
|
|
289
|
-
}
|
|
290
|
-
return {
|
|
291
|
-
tool_call_id: toolCall.id,
|
|
292
|
-
content: JSON.stringify({
|
|
293
|
-
success: result.success,
|
|
294
|
-
data: result.data,
|
|
295
|
-
message: result.message,
|
|
296
|
-
error: result.error
|
|
297
|
-
})
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
catch (error) {
|
|
301
|
-
return {
|
|
302
|
-
tool_call_id: toolCall.id,
|
|
303
|
-
content: JSON.stringify({
|
|
304
|
-
success: false,
|
|
305
|
-
error: error instanceof Error ? error.message : 'Unknown error'
|
|
306
|
-
})
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
});
|
|
310
|
-
return Promise.all(resultPromises);
|
|
311
|
-
}
|
|
312
|
-
// Proposals tool - full CRUD operations using @lovelybunch/core
|
|
173
|
+
// ─── Tool Execution Functions ────────────────────────────────────────────────
|
|
174
|
+
// These are unchanged from the previous implementation. They handle the actual
|
|
175
|
+
// business logic for each tool, called automatically by the AI SDK when the
|
|
176
|
+
// LLM makes tool calls.
|
|
313
177
|
async function executeProposalsToolDirect(args, _storage) {
|
|
314
178
|
const { operation, id, filters, proposal, updates } = args;
|
|
315
179
|
try {
|
|
@@ -381,7 +245,6 @@ async function executeProposalsToolDirect(args, _storage) {
|
|
|
381
245
|
}
|
|
382
246
|
}
|
|
383
247
|
catch (error) {
|
|
384
|
-
// Handle Zod validation errors specially
|
|
385
248
|
if (error instanceof ZodError) {
|
|
386
249
|
return {
|
|
387
250
|
success: false,
|
|
@@ -953,6 +816,7 @@ async function executeRoleContextToolDirect(args) {
|
|
|
953
816
|
return { success: false, error: error.message || 'Role context tool execution failed' };
|
|
954
817
|
}
|
|
955
818
|
}
|
|
819
|
+
// ─── Helper Functions ────────────────────────────────────────────────────────
|
|
956
820
|
function getContextBasePath() {
|
|
957
821
|
let basePath;
|
|
958
822
|
if (process.env.NODE_ENV === 'development' && process.env.GAIT_DEV_ROOT) {
|
|
@@ -1017,14 +881,14 @@ async function readKnowledgeDocument(basePath, filename) {
|
|
|
1017
881
|
fs.stat(filePath)
|
|
1018
882
|
]);
|
|
1019
883
|
const { data, content } = matter(raw);
|
|
1020
|
-
const
|
|
884
|
+
const normalizedMeta = normalizeKnowledgeMetadata(data);
|
|
1021
885
|
// Use file mtime for updated timestamp instead of frontmatter
|
|
1022
|
-
|
|
886
|
+
normalizedMeta.updated = stats.mtime.toISOString();
|
|
1023
887
|
const title = extractKnowledgeTitle(content, actualFilename);
|
|
1024
888
|
return {
|
|
1025
889
|
filename: actualFilename,
|
|
1026
890
|
title,
|
|
1027
|
-
metadata,
|
|
891
|
+
metadata: normalizedMeta,
|
|
1028
892
|
content
|
|
1029
893
|
};
|
|
1030
894
|
}
|
|
@@ -7,9 +7,9 @@ import { Context } from "hono";
|
|
|
7
7
|
* Get logging system status and configuration
|
|
8
8
|
*/
|
|
9
9
|
export declare function GET(c: Context): Promise<(Response & import("hono").TypedResponse<{
|
|
10
|
+
[x: string]: any;
|
|
10
11
|
currentFile: string;
|
|
11
12
|
sizeBytes: number;
|
|
12
|
-
lastSeq: number;
|
|
13
13
|
rotateBytes: number;
|
|
14
14
|
logsDir: string;
|
|
15
15
|
}, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
|
|
@@ -12,8 +12,8 @@ export declare function POST(c: Context): Promise<(Response & import("hono").Typ
|
|
|
12
12
|
run: {
|
|
13
13
|
id: string;
|
|
14
14
|
jobId: string;
|
|
15
|
-
trigger: import("@lovelybunch/
|
|
16
|
-
status: import("@lovelybunch/
|
|
15
|
+
trigger: import("@lovelybunch/types").ScheduledJobTrigger;
|
|
16
|
+
status: import("@lovelybunch/types").ScheduledJobRunStatus;
|
|
17
17
|
startedAt: string;
|
|
18
18
|
finishedAt?: string;
|
|
19
19
|
outputPath?: string;
|
|
@@ -10,8 +10,8 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
10
10
|
data: {
|
|
11
11
|
id: string;
|
|
12
12
|
jobId: string;
|
|
13
|
-
trigger: import("@lovelybunch/
|
|
14
|
-
status: import("@lovelybunch/
|
|
13
|
+
trigger: import("@lovelybunch/types").ScheduledJobTrigger;
|
|
14
|
+
status: import("@lovelybunch/types").ScheduledJobRunStatus;
|
|
15
15
|
startedAt: string;
|
|
16
16
|
finishedAt?: string;
|
|
17
17
|
outputPath?: string;
|
|
@@ -7,7 +7,7 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
7
7
|
runningCount: number;
|
|
8
8
|
jobs: {
|
|
9
9
|
id: string;
|
|
10
|
-
status: import("@lovelybunch/
|
|
10
|
+
status: import("@lovelybunch/types").ScheduledJobStatus;
|
|
11
11
|
nextRunAt?: string;
|
|
12
12
|
lastRunAt?: string;
|
|
13
13
|
timerActive: boolean;
|
|
@@ -13,7 +13,7 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
13
13
|
intent?: string;
|
|
14
14
|
content?: string;
|
|
15
15
|
author: {
|
|
16
|
-
type: import("@lovelybunch/
|
|
16
|
+
type: import("@lovelybunch/types").AuthorType;
|
|
17
17
|
id: string;
|
|
18
18
|
name: string;
|
|
19
19
|
email?: string;
|
|
@@ -48,7 +48,7 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
48
48
|
version: string;
|
|
49
49
|
name: string;
|
|
50
50
|
description: string;
|
|
51
|
-
type: import("@lovelybunch/
|
|
51
|
+
type: import("@lovelybunch/types").FeatureFlagType;
|
|
52
52
|
defaultValue: any;
|
|
53
53
|
scopes: string[];
|
|
54
54
|
targets: {
|
|
@@ -96,7 +96,7 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
96
96
|
minimumSampleSize: number;
|
|
97
97
|
testType: "two-tailed" | "one-tailed";
|
|
98
98
|
};
|
|
99
|
-
status: import("@lovelybunch/
|
|
99
|
+
status: import("@lovelybunch/types").ExperimentStatus;
|
|
100
100
|
startedAt?: string;
|
|
101
101
|
endedAt?: string;
|
|
102
102
|
}[];
|
|
@@ -134,7 +134,7 @@ export declare function GET(c: Context): Promise<(Response & import("hono").Type
|
|
|
134
134
|
schedule?: string;
|
|
135
135
|
rollbackPlan?: string;
|
|
136
136
|
};
|
|
137
|
-
status: import("@lovelybunch/
|
|
137
|
+
status: import("@lovelybunch/types").CPStatus;
|
|
138
138
|
comments?: {
|
|
139
139
|
id: string;
|
|
140
140
|
author: string;
|
|
@@ -177,7 +177,7 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
|
|
|
177
177
|
intent?: string;
|
|
178
178
|
content?: string;
|
|
179
179
|
author: {
|
|
180
|
-
type: import("@lovelybunch/
|
|
180
|
+
type: import("@lovelybunch/types").AuthorType;
|
|
181
181
|
id: string;
|
|
182
182
|
name: string;
|
|
183
183
|
email?: string;
|
|
@@ -212,7 +212,7 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
|
|
|
212
212
|
version: string;
|
|
213
213
|
name: string;
|
|
214
214
|
description: string;
|
|
215
|
-
type: import("@lovelybunch/
|
|
215
|
+
type: import("@lovelybunch/types").FeatureFlagType;
|
|
216
216
|
defaultValue: any;
|
|
217
217
|
scopes: string[];
|
|
218
218
|
targets: {
|
|
@@ -260,7 +260,7 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
|
|
|
260
260
|
minimumSampleSize: number;
|
|
261
261
|
testType: "two-tailed" | "one-tailed";
|
|
262
262
|
};
|
|
263
|
-
status: import("@lovelybunch/
|
|
263
|
+
status: import("@lovelybunch/types").ExperimentStatus;
|
|
264
264
|
startedAt?: string;
|
|
265
265
|
endedAt?: string;
|
|
266
266
|
}[];
|
|
@@ -298,7 +298,7 @@ export declare function PATCH(c: Context): Promise<(Response & import("hono").Ty
|
|
|
298
298
|
schedule?: string;
|
|
299
299
|
rollbackPlan?: string;
|
|
300
300
|
};
|
|
301
|
-
status: import("@lovelybunch/
|
|
301
|
+
status: import("@lovelybunch/types").CPStatus;
|
|
302
302
|
comments?: {
|
|
303
303
|
id: string;
|
|
304
304
|
author: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lovelybunch/api",
|
|
3
|
-
"version": "1.0.75-alpha.
|
|
3
|
+
"version": "1.0.75-alpha.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/server-with-static.js",
|
|
6
6
|
"exports": {
|
|
@@ -34,11 +34,13 @@
|
|
|
34
34
|
"license": "ISC",
|
|
35
35
|
"description": "Coconut API server",
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"@ai-sdk/anthropic": "^3.0.41",
|
|
37
38
|
"@hono/node-server": "^1.13.7",
|
|
38
39
|
"@hono/node-ws": "^1.0.6",
|
|
39
|
-
"@lovelybunch/core": "^1.0.75-alpha.
|
|
40
|
-
"@lovelybunch/mcp": "^1.0.75-alpha.
|
|
41
|
-
"@lovelybunch/types": "^1.0.75-alpha.
|
|
40
|
+
"@lovelybunch/core": "^1.0.75-alpha.5",
|
|
41
|
+
"@lovelybunch/mcp": "^1.0.75-alpha.5",
|
|
42
|
+
"@lovelybunch/types": "^1.0.75-alpha.5",
|
|
43
|
+
"ai": "^6.0.79",
|
|
42
44
|
"arctic": "^1.9.2",
|
|
43
45
|
"bcrypt": "^5.1.1",
|
|
44
46
|
"cookie": "^0.6.0",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as a,A as p,j as e,
|
|
1
|
+
import{r as a,A as p,j as e,H as v,bh as y,B as N,v as w,C as b}from"./index-BlLRLvWP.js";import{C as c,a as d,b as k,c as C}from"./card-BguljVtN.js";import{B as m}from"./badge-DvLOhob-.js";import{R as E}from"./refresh-cw-SQsUc3_C.js";const A=5e3;function $(){const[n,o]=a.useState([]),[i,x]=a.useState(!0),[h,u]=a.useState(new Set),l=a.useCallback(async()=>{x(!0);try{const s=await fetch(`${p}/api/v1/events?limit=${A}`);if(!s.ok)throw new Error("Failed to load events");const t=await s.json();o(Array.isArray(t.items)?[...t.items].reverse():[])}catch(s){console.error("Failed to load events:",s),o([])}finally{x(!1)}},[]),g=a.useCallback(s=>{u(t=>{const r=new Set(t);return r.has(s)?r.delete(s):r.add(s),r})},[]);a.useEffect(()=>{l()},[l]);const f=s=>{if(!s)return"Unknown time";try{return new Date(s).toLocaleString()}catch{return s}},j=s=>{switch(s?.toLowerCase()){case"error":return"bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200";case"warn":case"warning":return"bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200";case"info":return"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200";case"debug":return"bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200";default:return"bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200"}};return i?e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-2xl font-bold tracking-tight",children:"Activity"}),e.jsx("p",{className:"text-muted-foreground",children:"View system activity and events"})]}),e.jsx(c,{children:e.jsx(d,{className:"pt-6",children:e.jsxs("div",{className:"flex items-center justify-center",children:[e.jsx(v,{className:"h-8 w-8 animate-spin text-muted-foreground"}),e.jsx("span",{className:"ml-2 text-muted-foreground",children:"Loading events..."})]})})})]}):n.length===0?e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-2xl font-bold tracking-tight",children:"Activity"}),e.jsx("p",{className:"text-muted-foreground",children:"View system activity and events"})]}),e.jsx(c,{children:e.jsx(d,{className:"pt-6",children:e.jsxs("div",{className:"text-center",children:[e.jsx(y,{className:"mx-auto h-12 w-12 text-muted-foreground"}),e.jsx("h3",{className:"mt-4 text-lg font-semibold",children:"No Events Found"}),e.jsx("p",{className:"mt-2 text-sm text-muted-foreground",children:"Activity events will appear here as they occur."})]})})})]}):e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-2xl font-bold tracking-tight",children:"Activity"}),e.jsxs("p",{className:"text-muted-foreground",children:["View system activity and events (",n.length," events)"]})]}),e.jsxs(N,{variant:"outline",size:"sm",onClick:()=>void l(),disabled:i,children:[e.jsx(E,{className:`h-4 w-4 mr-2 ${i?"animate-spin":""}`}),"Refresh"]})]}),e.jsx("div",{className:"space-y-3",children:n.map(s=>{const t=h.has(s.seq);return e.jsxs(c,{className:"transition-colors",children:[e.jsx(k,{className:"py-3 cursor-pointer hover:bg-muted/30",onClick:()=>g(s.seq),children:e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"flex items-start gap-2 flex-1 min-w-0",children:[t?e.jsx(w,{className:"h-4 w-4 mt-0.5 text-muted-foreground shrink-0"}):e.jsx(b,{className:"h-4 w-4 mt-0.5 text-muted-foreground shrink-0"}),e.jsxs("div",{className:"space-y-1 flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsxs(C,{className:"text-sm font-medium",children:["#",s.seq]}),s.kind&&e.jsx(m,{variant:"outline",className:"text-xs",children:s.kind}),s.level&&e.jsx(m,{className:`text-xs ${j(s.level)}`,children:s.level})]}),s.message&&e.jsx("p",{className:`text-sm text-muted-foreground ${t?"":"truncate"}`,children:s.message})]})]}),e.jsx("span",{className:"text-xs text-muted-foreground whitespace-nowrap",children:f(s.ts)})]})}),t&&e.jsx(d,{className:"pt-0 pb-4",children:e.jsx("pre",{className:"text-xs bg-muted p-3 rounded-md overflow-x-auto",children:JSON.stringify(s,null,2)})})]},s.seq)})})]})}export{$ as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{P as A,u as E,r as h,j as e,B as i,L as d,Q as k,V as B,p as S,A as N}from"./index-BlLRLvWP.js";import{C as l,b as o,a as m,c as f,d as z}from"./card-BguljVtN.js";import{B as v}from"./badge-DvLOhob-.js";import{A as u}from"./arrow-left-DZzHrGWA.js";const D=t=>t?Array.isArray(t)?t.filter(r=>typeof r=="string").map(r=>r.trim()).filter(Boolean):typeof t=="string"?t.split(",").map(r=>r.trim()).filter(Boolean):[]:[],c={blue:{bg:"#dbeafe",border:"#2563eb",text:"#1e40af"},green:{bg:"#dcfce7",border:"#16a34a",text:"#166534"},red:{bg:"#fee2e2",border:"#dc2626",text:"#991b1b"},emerald:{bg:"#d1fae5",border:"#10b981",text:"#047857"},purple:{bg:"#f3e8ff",border:"#9333ea",text:"#6b21a8"},orange:{bg:"#fed7aa",border:"#ea580c",text:"#9a3412"},yellow:{bg:"#fef9c3",border:"#eab308",text:"#854d0e"},teal:{bg:"#ccfbf1",border:"#14b8a6",text:"#0f766e"},indigo:{bg:"#e0e7ff",border:"#6366f1",text:"#4338ca"},pink:{bg:"#fce7f3",border:"#ec4899",text:"#9f1239"},cyan:{bg:"#cffafe",border:"#06b6d4",text:"#155e75"},slate:{bg:"#f1f5f9",border:"#475569",text:"#334155"},gray:{bg:"#f3f4f6",border:"#6b7280",text:"#374151"}};function F(){const t=A(),r=E(),[s,y]=h.useState(null),[w,j]=h.useState(!0),[p,x]=h.useState(null);h.useEffect(()=>{async function a(){try{j(!0);const g=await(await fetch(`${N}/api/v1/agents/${t.id}`)).json();g.success?y(g.document):x(g.error||"Failed to fetch agent")}catch(n){x(n instanceof Error?n.message:"Unknown error")}finally{j(!1)}}t.id&&a()},[t.id]);const C=async()=>{if(!(!s||!confirm("Are you sure you want to delete this agent?")))try{const n=await(await fetch(`${N}/api/v1/agents/${s.filename.replace(".md","")}`,{method:"DELETE"})).json();n.success?r("/agents"):x(n.error?.message||"Failed to delete agent")}catch(a){x(a instanceof Error?a.message:"Unknown error")}};if(w)return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex-1",children:[e.jsx("div",{className:"h-8 bg-muted rounded w-64 animate-pulse"}),e.jsx("div",{className:"h-4 bg-muted rounded w-32 animate-pulse mt-2"})]}),e.jsx("div",{className:"flex items-center gap-2",children:e.jsx(i,{variant:"ghost",size:"sm",asChild:!0,className:"px-2 hover:bg-transparent",children:e.jsx(d,{to:"/agents",className:"flex items-center text-muted-foreground hover:text-foreground transition-colors",children:e.jsx(u,{className:"h-4 w-4"})})})})]}),e.jsx(l,{children:e.jsxs(o,{children:[e.jsx("div",{className:"h-6 bg-muted rounded w-48 animate-pulse"}),e.jsx("div",{className:"h-4 bg-muted rounded w-64 animate-pulse"})]})})]});if(p||!s)return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold tracking-tight",children:"Agent Not Found"}),e.jsx("p",{className:"text-muted-foreground",children:"The requested agent could not be found"})]}),e.jsx("div",{className:"flex items-center gap-2",children:e.jsx(i,{variant:"ghost",size:"sm",asChild:!0,className:"px-2 hover:bg-transparent",children:e.jsx(d,{to:"/agents",className:"flex items-center text-muted-foreground hover:text-foreground transition-colors",children:e.jsx(u,{className:"h-4 w-4"})})})})]}),e.jsx(l,{children:e.jsx(m,{className:"pt-6",children:e.jsx("div",{className:"text-center",children:e.jsx("p",{className:"text-destructive",children:p||"Agent not found"})})})})]});const b=D(s.metadata.tools);return e.jsxs("div",{className:"space-y-6",children:[e.jsx("div",{className:"space-y-1",children:e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsx("h1",{className:"text-xl sm:text-2xl font-bold tracking-tight",children:s.metadata.name}),e.jsxs("div",{className:"flex items-center gap-2 flex-shrink-0",children:[e.jsx(i,{variant:"ghost",size:"sm",asChild:!0,children:e.jsx(d,{to:"/agents",className:"flex items-center gap-1 text-muted-foreground hover:text-foreground transition-colors",children:e.jsx(u,{className:"h-4 w-4"})})}),e.jsx(i,{variant:"outline",size:"sm",asChild:!0,children:e.jsxs(d,{to:`/agents/${s.filename.replace(".md","")}/edit`,children:[e.jsx(k,{className:"h-4 w-4 sm:mr-2"}),e.jsx("span",{className:"hidden sm:inline",children:"Edit"})]})}),e.jsxs(i,{variant:"destructive",size:"sm",onClick:C,children:[e.jsx(B,{className:"h-4 w-4 sm:mr-2"}),e.jsx("span",{className:"hidden sm:inline",children:"Delete"})]})]})]})}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-3 gap-6",children:[e.jsxs("div",{className:"lg:col-span-2 space-y-6",children:[e.jsxs(l,{children:[e.jsx(o,{children:e.jsx(f,{children:"Description"})}),e.jsx(m,{children:e.jsx("p",{children:s.metadata.description})})]}),s.content&&e.jsxs(l,{children:[e.jsxs(o,{children:[e.jsx(f,{children:"Instructions"}),e.jsx(z,{children:"System prompt and behavior instructions for this agent"})]}),e.jsx(m,{children:e.jsx("pre",{className:"whitespace-pre-wrap text-sm bg-muted p-4 rounded-md",children:s.content})})]})]}),e.jsxs("div",{className:"space-y-6",children:[e.jsxs(l,{children:[e.jsx(o,{children:e.jsx(f,{children:"Actions"})}),e.jsx(m,{className:"space-y-2",children:e.jsx(i,{variant:"default",className:"w-full justify-start",asChild:!0,children:e.jsxs(d,{to:`/terminal/ag-${s.filename.replace(".md","")}`,children:[e.jsx(S,{className:"h-4 w-4 mr-2"}),"Start Agent"]})})})]}),e.jsxs(l,{children:[e.jsx(o,{children:e.jsx(f,{children:"Information"})}),e.jsxs(m,{className:"space-y-2",children:[s.metadata.color&&e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium mb-2",children:"Color"}),e.jsx(v,{variant:"outline",className:"capitalize border-2",style:{backgroundColor:c[s.metadata.color]?.bg||c.blue.bg,color:c[s.metadata.color]?.text||c.blue.text,borderColor:c[s.metadata.color]?.border||c.blue.border},children:s.metadata.color})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:"Tools"}),b.length>0?e.jsx("div",{className:"flex flex-wrap gap-2 mt-1",children:b.map(a=>e.jsx(v,{variant:"secondary",children:a},a))}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"No specific tools configured - inherits all tools"})]})]})]})]})]})]})}export{F as default};
|