mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-07 23:42:21 +02:00
Consolidate Odysseus agent harness and tool contracts
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { topPortalZ } from './toolWindowZOrder.js';
|
||||
import uiModule from './ui.js?v=20260908weekhoverfix1';
|
||||
import uiModule from './ui.js?v=20260916largetoolscroll1';
|
||||
import sessionModule from './sessions.js';
|
||||
import spinnerModule from './spinner.js';
|
||||
import markdownModule from './markdown.js';
|
||||
@@ -37,17 +37,26 @@ function _isEmailDocument(doc) {
|
||||
return String(doc?.language || '').toLowerCase() === 'email';
|
||||
}
|
||||
|
||||
function _documentExport(doc, extMap) {
|
||||
function _documentExport(doc, extMap, format = 'original') {
|
||||
const email = _isEmailDocument(doc);
|
||||
const ext = email ? '.eml' : (extMap[doc?.language] || '.txt');
|
||||
const requestedFormat = String(format || 'original').toLowerCase();
|
||||
const forcedMarkdown = requestedFormat === 'markdown' || requestedFormat === 'md';
|
||||
const forcedText = requestedFormat === 'text' || requestedFormat === 'txt';
|
||||
const ext = forcedMarkdown ? '.md' : forcedText ? '.txt'
|
||||
: email ? '.eml' : (extMap[doc?.language] || '.txt');
|
||||
const title = String(doc?.title || 'document').trim() || 'document';
|
||||
const filename = title.toLowerCase().endsWith(ext) ? title : title + ext;
|
||||
// Email drafts use an internal header/body separator for the editor. Turn it
|
||||
// into the blank line required by RFC 5322 when exporting as .eml.
|
||||
const content = email
|
||||
const content = email && !forcedMarkdown && !forcedText
|
||||
? String(doc?.current_content || '').replace(/\r?\n---\r?\n/, '\r\n\r\n')
|
||||
: String(doc?.current_content || '');
|
||||
return { filename, content, type: email ? 'message/rfc822' : 'text/plain;charset=utf-8' };
|
||||
return {
|
||||
filename,
|
||||
content,
|
||||
type: forcedMarkdown ? 'text/markdown;charset=utf-8'
|
||||
: email && !forcedText ? 'message/rfc822' : 'text/plain;charset=utf-8',
|
||||
};
|
||||
}
|
||||
|
||||
const _LIBRARY_SORT_ICONS = {
|
||||
@@ -843,14 +852,14 @@ function _setLibraryCountChipContent(chip, label, count) {
|
||||
exportItem.className = 'dropdown-item-compact';
|
||||
exportItem.style.cssText = 'background:none;border:none;width:100%;';
|
||||
exportItem.innerHTML = _di(_exportIco) + '<span>Export</span>';
|
||||
const exportDocumentFile = async () => {
|
||||
const exportDocumentFile = async (format = 'original') => {
|
||||
hideCardDropdown();
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/api/document/${doc.id}`);
|
||||
if (!res.ok) throw new Error('Failed');
|
||||
const full = await res.json();
|
||||
const extMap = { javascript: '.js', python: '.py', html: '.html', svg: '.svg', css: '.css', markdown: '.md', json: '.json', yaml: '.yml', bash: '.sh', sql: '.sql', rust: '.rs', go: '.go', java: '.java', c: '.c', cpp: '.cpp', typescript: '.ts', ruby: '.rb', php: '.php', xml: '.xml', toml: '.toml', ini: '.ini' };
|
||||
const exported = _documentExport(full, extMap);
|
||||
const exported = _documentExport(full, extMap, format);
|
||||
const blob = new Blob([exported.content], { type: exported.type });
|
||||
const a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
@@ -1036,7 +1045,25 @@ function _setLibraryCountChipContent(chip, label, count) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
_showLibDropdown(mobileMoreBtn, [
|
||||
{ label: 'Export file', icon: 'export', action: () => expandedExportBtn.click() },
|
||||
{
|
||||
label: 'Export file ›',
|
||||
icon: 'export',
|
||||
action: () => {
|
||||
const formatItems = [
|
||||
{ label: 'Original format', icon: 'export', action: () => expandedExportBtn.click() },
|
||||
{ label: 'Markdown (.md)', action: () => exportDocumentFile('markdown') },
|
||||
{ label: 'Plain text (.txt)', action: () => exportDocumentFile('text') },
|
||||
];
|
||||
const language = String(doc.language || '').toLowerCase();
|
||||
if (language === 'docx' || language === 'pdf') {
|
||||
formatItems.push(
|
||||
{ label: 'PDF (.pdf)', action: () => exportDocumentFile('pdf') },
|
||||
{ label: 'Word (.docx)', action: () => exportDocumentFile('docx') },
|
||||
);
|
||||
}
|
||||
_showLibDropdown(mobileMoreBtn, formatItems);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: _libraryArchivedView ? 'Restore document' : 'Archive document',
|
||||
icon: _libraryArchivedView ? 'restore' : 'archive',
|
||||
@@ -1688,7 +1715,7 @@ function _setLibraryCountChipContent(chip, label, count) {
|
||||
'.scss': 'css', '.sass': 'css', '.less': 'css',
|
||||
'.csv': 'csv', '.tsv': 'csv',
|
||||
'.xlsx': 'csv', '.xls': 'csv', '.ods': 'csv',
|
||||
'.docx': 'markdown', '.doc': 'markdown',
|
||||
'.docx': 'docx', '.doc': 'markdown',
|
||||
};
|
||||
|
||||
let imported = 0;
|
||||
@@ -1707,6 +1734,7 @@ function _setLibraryCountChipContent(chip, label, count) {
|
||||
|
||||
const isSpreadsheet = ['.xlsx', '.xls', '.ods'].includes(ext);
|
||||
const isPdf = ext === '.pdf';
|
||||
const isDocx = ext === '.docx';
|
||||
|
||||
if (isPdf) {
|
||||
// Backend handles save + AcroForm detection in one shot — picks the
|
||||
@@ -1727,6 +1755,24 @@ function _setLibraryCountChipContent(chip, label, count) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isDocx) {
|
||||
// Preserve the original upload so the document panel can render a
|
||||
// Word-style preview and offer conversion/export actions later.
|
||||
const fd = new FormData();
|
||||
fd.append('file', file);
|
||||
const res = await fetch(`${API_BASE}/api/documents/import-docx`, {
|
||||
method: 'POST',
|
||||
body: fd,
|
||||
});
|
||||
if (!res.ok) {
|
||||
let _e = `HTTP ${res.status}`;
|
||||
try { const _j = await res.json(); _e = _j.detail || _j.error || _e; } catch {}
|
||||
throw new Error('DOCX import failed: ' + _e);
|
||||
}
|
||||
imported++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isSpreadsheet) {
|
||||
// Multi-sheet: create one document per sheet
|
||||
await ensureXLSX();
|
||||
|
||||
Reference in New Issue
Block a user