@endlessblink/like-i-said-v2
Version:
Task Management & Memory for Claude - Track tasks, remember context, and maintain continuity across sessions with 27 powerful tools. Works with Claude Desktop and Claude Code.
42 lines (32 loc) • 7.05 kB
JavaScript
class p{constructor(e="http://localhost:11434",t={}){this.baseUrl=e,this.options={model:t.model||"llama3.1:8b",temperature:t.temperature||.1,maxTokens:t.maxTokens||200,batchSize:t.batchSize||5,requestTimeout:t.requestTimeout||3e4,...t}}async isAvailable(){try{return(await fetch(`${this.baseUrl}/api/version`,{method:"GET",headers:{"Content-Type":"application/json"},signal:AbortSignal.timeout(5e3)})).ok}catch(e){return console.warn("Ollama server not available:",e.message),!1}}async listModels(){try{const e=await fetch(`${this.baseUrl}/api/tags`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok)throw new Error(`HTTP ${e.status}: ${e.statusText}`);return(await e.json()).models||[]}catch(e){return console.error("Failed to list Ollama models:",e),[]}}async enhanceMemory(e,t={}){const o=this.buildEnhancementPrompt(e,t);try{const s=await this.generateCompletion(o);return this.parseEnhancementResponse(s)}catch(s){throw console.error("Ollama enhancement error:",s),new Error(`Local AI enhancement failed: ${s.message}`)}}async enhanceMemoriesBatch(e,t=null){const o=[],s=this.createBatches(e,this.options.batchSize);console.log(`🤖 Processing ${e.length} memories in ${s.length} batches of ${this.options.batchSize}`);for(let a=0;a<s.length;a++){const n=s[a];console.log(`📦 Processing batch ${a+1}/${s.length}`);const c=n.map(async(i,m)=>{try{const r=await this.enhanceMemory(i.content,i);return t==null||t(a*this.options.batchSize+m+1,e.length),{memory:i,enhancement:r,success:!0}}catch(r){return console.error(`Failed to enhance memory ${i.id}:`,r),{memory:i,error:r.message,success:!1}}}),l=await Promise.all(c);o.push(...l),a<s.length-1&&await this.delay(1e3)}return o}async generateCompletion(e){const t={model:this.options.model,prompt:e,stream:!1,options:{temperature:this.options.temperature,num_predict:this.options.maxTokens,stop:["</json>",`
---`,`
End:`]}},o=new AbortController,s=setTimeout(()=>o.abort(),this.options.requestTimeout);try{const a=await fetch(`${this.baseUrl}/api/generate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),signal:o.signal});if(clearTimeout(s),!a.ok)throw new Error(`Ollama API error: ${a.status} ${a.statusText}`);const n=await a.json();if(!n.response)throw new Error("No response from Ollama model");return n.response.trim()}catch(a){throw clearTimeout(s),a.name==="AbortError"?new Error("Request timeout - model may be too slow"):a}}buildEnhancementPrompt(e,t={}){const o=t.category||"general",s={code:"Use format: [Technology] [Component]: [Purpose/Action]. Focus on language, framework, component name, and main purpose. Prioritize function over implementation details. Include version numbers and specific technologies when relevant.",work:"Use format: [Project] [Action]: [Specific Task]. Include project context, action verb, and specific outcome. Prioritize deliverables over process. Reference project phases, sprints, or milestones when relevant.",research:"Use format: [Topic]: [Specific Focus/Finding]. Include domain and specific area of focus. Prioritize key insights over general topics. Reference methodologies and measurable outcomes.",conversations:"Use format: [Context]: [Main Topic/Decision]. Include communication type, key participants, and main topic. Prioritize decisions and outcomes over general discussion.",personal:"Use format: [Category]: [Specific Preference/Insight]. Include personal context and specific area. Prioritize actionable insights over general thoughts.",preferences:"Use format: [Category]: [Specific Preference/Insight]. Include personal context and specific area. Prioritize actionable insights over general thoughts.",general:'Use appropriate format based on content type. Focus on specificity, clarity, and actionability. Avoid vague terms like "stuff", "things", "various".'},a=s[o]||s.general;return`You are a memory enhancement specialist. Generate a concise title and description following these strict rules:
CONTENT CATEGORY: ${o}
CATEGORY RULES: ${a}
MANDATORY REQUIREMENTS:
- Title: Maximum 50 characters, use title case, no periods unless abbreviation
- Description: Maximum 140 characters, active voice, complement title (no repetition)
- Use specific terms over generic ones (avoid "implementation", "system", "process")
- Include key identifiers (project names, technologies, specific issues)
- For technical content: include technologies, versions, specific components
- For tasks: use action-oriented language with clear outcomes
- For research: emphasize findings and applications
- For conversations: focus on decisions and key outcomes
FORBIDDEN PATTERNS:
- Vague descriptors: "various", "multiple", "different", "several"
- Redundant prefixes: "How to", "Guide to", "Information about"
- Obvious statements: "This is about", "Contains information on"
- Excessive adjectives: "comprehensive", "ultimate", "complete", "full"
- Generic project names: "Project", "System", "Application"
CONTENT TO ANALYZE:
${e.substring(0,2e3)}${e.length>2e3?"...":""}
Generate ONLY a JSON response with:
- title: Specific, clear, follows category format rules
- summary: Informative, complements title, includes context/impact
JSON format:
{
"title": "your title here",
"summary": "your summary here"
}
Respond with ONLY the JSON, no additional text:`}parseEnhancementResponse(e){try{const t=e.replace(/^[^{]*/,"").replace(/[^}]*$/,"").replace(/```json\s*/,"").replace(/```\s*$/,"").trim(),o=JSON.parse(t);if(!o.title||!o.summary)throw new Error("Missing title or summary in response");return{title:o.title.substring(0,50).trim(),summary:o.summary.substring(0,140).trim()}}catch(t){const o=e.match(/"title":\s*"([^"]+)"/i),s=e.match(/"summary":\s*"([^"]+)"/i);if(o&&s)return{title:o[1].substring(0,50).trim(),summary:s[1].substring(0,140).trim()};throw new Error(`Failed to parse AI response: ${t.message}`)}}createBatches(e,t){const o=[];for(let s=0;s<e.length;s+=t)o.push(e.slice(s,s+t));return o}delay(e){return new Promise(t=>setTimeout(t,e))}static getModelRecommendations(){return{lightweight:[{name:"llama3.1:8b",description:"Fast, good quality (4GB RAM)"},{name:"llama3.2:3b",description:"Very fast, decent quality (2GB RAM)"},{name:"phi3:mini",description:"Ultra-fast, basic quality (1GB RAM)"}],balanced:[{name:"llama3.1:8b",description:"Best all-around choice (4GB RAM)"},{name:"mistral:7b",description:"Good alternative (4GB RAM)"},{name:"codellama:7b",description:"Better for code content (4GB RAM)"}],quality:[{name:"llama3.1:70b",description:"Highest quality (40GB+ RAM)"},{name:"mixtral:8x7b",description:"Excellent quality (26GB RAM)"},{name:"llama3.1:13b",description:"High quality (8GB RAM)"}]}}static estimateProcessingTime(e,t="llama3.1:8b"){const s={"phi3:mini":2,"llama3.2:3b":3,"llama3.1:8b":5,"mistral:7b":6,"llama3.1:13b":8,"mixtral:8x7b":15,"llama3.1:70b":30}[t]||5,a=e*s,n=Math.ceil(a/60);return{seconds:a,minutes:n,estimate:n<2?`~${a} seconds`:`~${n} minutes`}}}export{p as OllamaClient,p as default};
//# sourceMappingURL=ollama-client-db87e49c.js.map