tuna-agent 0.1.77 → 0.1.78
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.
|
@@ -63,6 +63,7 @@ export declare function handleCreateCharacter(ws: AgentWebSocketClient, code: st
|
|
|
63
63
|
export declare function handleSaveCharacterSelection(ws: AgentWebSocketClient, code: string, taskId: string, characterId: string, selectedImages: string[]): void;
|
|
64
64
|
/**
|
|
65
65
|
* Sync apps from the agent's knowledge base.
|
|
66
|
-
*
|
|
66
|
+
* Searches all folders (2 levels deep) for the "App Info" document,
|
|
67
|
+
* then parses the multi-app markdown format.
|
|
67
68
|
*/
|
|
68
69
|
export declare function handleSyncApps(ws: AgentWebSocketClient, code: string, taskId: string, apiUrl: string, agentToken: string, agentId: string): Promise<void>;
|
|
@@ -896,7 +896,8 @@ const APP_COLORS = [
|
|
|
896
896
|
];
|
|
897
897
|
/**
|
|
898
898
|
* Sync apps from the agent's knowledge base.
|
|
899
|
-
*
|
|
899
|
+
* Searches all folders (2 levels deep) for the "App Info" document,
|
|
900
|
+
* then parses the multi-app markdown format.
|
|
900
901
|
*/
|
|
901
902
|
export async function handleSyncApps(ws, code, taskId, apiUrl, agentToken, agentId) {
|
|
902
903
|
try {
|
|
@@ -916,55 +917,33 @@ export async function handleSyncApps(ws, code, taskId, apiUrl, agentToken, agent
|
|
|
916
917
|
}
|
|
917
918
|
return json.data;
|
|
918
919
|
};
|
|
919
|
-
//
|
|
920
|
+
// Collect all documents (2 levels deep)
|
|
921
|
+
const allDocs = [];
|
|
920
922
|
const rootData = await knowledgeApi('GET', `/agent-knowledge?agent_id=${agentId}`);
|
|
921
|
-
const
|
|
922
|
-
|
|
923
|
-
const apps = [];
|
|
924
|
-
let colorIdx = 0;
|
|
925
|
-
for (const item of items) {
|
|
926
|
-
const nameLower = item.name.toLowerCase();
|
|
927
|
-
const descLower = (item.description || '').toLowerCase();
|
|
928
|
-
const isApp = nameLower.includes('app') ||
|
|
929
|
-
descLower.includes('app') ||
|
|
930
|
-
descLower.includes('application') ||
|
|
931
|
-
descLower.includes('mobile app') ||
|
|
932
|
-
descLower.includes('product');
|
|
933
|
-
if (!isApp)
|
|
934
|
-
continue;
|
|
923
|
+
const rootItems = rootData.items || [];
|
|
924
|
+
for (const item of rootItems) {
|
|
935
925
|
if (item.kind === 'folder') {
|
|
936
926
|
const folderData = await knowledgeApi('GET', `/agent-knowledge?agent_id=${agentId}&parent_id=${item._id}`);
|
|
937
|
-
const
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
for (const child of children) {
|
|
941
|
-
if (child.kind === 'document') {
|
|
942
|
-
const doc = await knowledgeApi('GET', `/agent-knowledge/${child._id}`);
|
|
943
|
-
features.push(..._extractFeatures(doc.content || ''));
|
|
944
|
-
if (!appDesc && doc.description)
|
|
945
|
-
appDesc = doc.description;
|
|
946
|
-
}
|
|
927
|
+
for (const child of (folderData.items || [])) {
|
|
928
|
+
if (child.kind !== 'folder')
|
|
929
|
+
allDocs.push(child);
|
|
947
930
|
}
|
|
948
|
-
apps.push({
|
|
949
|
-
id: item._id,
|
|
950
|
-
name: item.name,
|
|
951
|
-
description: appDesc,
|
|
952
|
-
features: [...new Set(features)].slice(0, 20),
|
|
953
|
-
color: APP_COLORS[colorIdx++ % APP_COLORS.length],
|
|
954
|
-
});
|
|
955
931
|
}
|
|
956
|
-
else
|
|
957
|
-
|
|
958
|
-
apps.push({
|
|
959
|
-
id: item._id,
|
|
960
|
-
name: item.name,
|
|
961
|
-
description: item.description || doc.description || '',
|
|
962
|
-
features: [...new Set(_extractFeatures(doc.content || ''))].slice(0, 20),
|
|
963
|
-
color: APP_COLORS[colorIdx++ % APP_COLORS.length],
|
|
964
|
-
});
|
|
932
|
+
else {
|
|
933
|
+
allDocs.push(item);
|
|
965
934
|
}
|
|
966
935
|
}
|
|
967
|
-
|
|
936
|
+
// Find "App Info" document (or any doc with "app info" in name)
|
|
937
|
+
const appInfoDoc = allDocs.find(d => d.name.toLowerCase().includes('app info'));
|
|
938
|
+
let apps = [];
|
|
939
|
+
if (appInfoDoc) {
|
|
940
|
+
const doc = await knowledgeApi('GET', `/agent-knowledge/${appInfoDoc._id}`);
|
|
941
|
+
apps = _parseAppInfoDocument(doc.content || '');
|
|
942
|
+
console.log(`[sync_apps] Parsed ${apps.length} app(s) from "${appInfoDoc.name}"`);
|
|
943
|
+
}
|
|
944
|
+
else {
|
|
945
|
+
console.log('[sync_apps] No "App Info" document found in knowledge');
|
|
946
|
+
}
|
|
968
947
|
ws.sendExtensionEvent(code, {
|
|
969
948
|
type: 'sync_apps_result',
|
|
970
949
|
apps,
|
|
@@ -982,27 +961,54 @@ export async function handleSyncApps(ws, code, taskId, apiUrl, agentToken, agent
|
|
|
982
961
|
ws.sendExtensionDone(code, taskId, { error });
|
|
983
962
|
}
|
|
984
963
|
}
|
|
985
|
-
/**
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
const
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
964
|
+
/**
|
|
965
|
+
* Parse the multi-app markdown document format.
|
|
966
|
+
* Each app starts with `# App Name - Tagline` and is separated by `---`.
|
|
967
|
+
* Features are numbered lists under `## Features`.
|
|
968
|
+
*/
|
|
969
|
+
function _parseAppInfoDocument(content) {
|
|
970
|
+
// Split by horizontal rules (---) into app sections
|
|
971
|
+
const sections = content.split(/\n---\n/).filter(s => s.trim());
|
|
972
|
+
const apps = [];
|
|
973
|
+
for (let i = 0; i < sections.length; i++) {
|
|
974
|
+
const section = sections[i];
|
|
975
|
+
// Extract app name from first H1: # App Name - Tagline
|
|
976
|
+
const h1Match = section.match(/^#\s+(.+?)(?:\s*\n|$)/m);
|
|
977
|
+
if (!h1Match)
|
|
978
|
+
continue;
|
|
979
|
+
const fullTitle = h1Match[1].trim();
|
|
980
|
+
// Split "Name - Tagline" at first " - "
|
|
981
|
+
const dashIdx = fullTitle.indexOf(' - ');
|
|
982
|
+
const name = dashIdx > 0 ? fullTitle.substring(0, dashIdx).trim() : fullTitle;
|
|
983
|
+
const tagline = dashIdx > 0 ? fullTitle.substring(dashIdx + 3).trim() : '';
|
|
984
|
+
// Extract ID from `- **ID:** \`xxx\``
|
|
985
|
+
const idMatch = section.match(/\*\*ID:\*\*\s*`([^`]+)`/);
|
|
986
|
+
const appId = idMatch ? idMatch[1] : name.toLowerCase().replace(/\s+/g, '-');
|
|
987
|
+
// Extract description from ## Promotional Text > blockquote
|
|
988
|
+
const promoMatch = section.match(/## Promotional Text\s*\n>\s*(.+)/);
|
|
989
|
+
const description = promoMatch ? promoMatch[1].trim() : tagline;
|
|
990
|
+
// Extract features from numbered list under ## Features
|
|
991
|
+
const features = [];
|
|
992
|
+
const featSection = section.match(/## Features\n([\s\S]*?)(?=\n##|\n---|\n_Last|$)/);
|
|
993
|
+
if (featSection) {
|
|
994
|
+
const featRegex = /^\d+\.\s+\*\*([^*]+)\*\*/gm;
|
|
995
|
+
let m;
|
|
996
|
+
while ((m = featRegex.exec(featSection[1])) !== null) {
|
|
997
|
+
features.push(m[1].trim());
|
|
1002
998
|
}
|
|
1003
999
|
}
|
|
1000
|
+
// Skip metadata-only sections (like _Last synced_)
|
|
1001
|
+
if (!name || name.startsWith('_'))
|
|
1002
|
+
continue;
|
|
1003
|
+
apps.push({
|
|
1004
|
+
id: appId,
|
|
1005
|
+
name,
|
|
1006
|
+
description,
|
|
1007
|
+
features,
|
|
1008
|
+
color: APP_COLORS[i % APP_COLORS.length],
|
|
1009
|
+
});
|
|
1004
1010
|
}
|
|
1005
|
-
return
|
|
1011
|
+
return apps;
|
|
1006
1012
|
}
|
|
1007
1013
|
function _sleep(ms) {
|
|
1008
1014
|
return new Promise(resolve => setTimeout(resolve, ms));
|