diff --git a/.github/workflows/porter-app-4689-merge-2-dev.yml b/.github/workflows/porter-app-4689-merge-2-dev.yml new file mode 100644 index 0000000..1dd49f8 --- /dev/null +++ b/.github/workflows/porter-app-4689-merge-2-dev.yml @@ -0,0 +1,27 @@ +"on": + push: + branches: + - dev +name: Deploy to merge-2-dev +jobs: + porter-deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set Github tag + id: vars + run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT + - name: Setup porter + uses: porter-dev/setup-porter@v0.1.0 + - name: Deploy stack + timeout-minutes: 30 + run: porter apply + env: + PORTER_APP_NAME: merge-2-dev + PORTER_CLUSTER: "4689" + PORTER_DEPLOYMENT_TARGET_ID: 4a24a192-04c8-421f-8fc2-22db1714fdc0 + PORTER_HOST: https://dashboard.porter.run + PORTER_PROJECT: "15081" + PORTER_TAG: ${{ steps.vars.outputs.sha_short }} + PORTER_TOKEN: ${{ secrets.PORTER_APP_15081_1175030936 }} diff --git a/LICENSE b/LICENSE index 1f93f13..bfb28bf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Mentra Community +Copyright (c) 2025 Mentra Labs, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docker/Dockerfile b/docker/Dockerfile index fffcc9c..f6ff7f7 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -8,5 +8,7 @@ RUN bun install --frozen-lockfile # Copy the entire application code COPY . . -# Expose the port (Porter uses 80) -EXPOSE 80 +# Expose the port (MentraOS default: 3000) +EXPOSE 3000 + +CMD ["bun", "src/index.ts"] diff --git a/src/frontend/pages/InsightsInterface.tsx b/src/frontend/pages/InsightsInterface.tsx index 2bf39f9..a745fae 100644 --- a/src/frontend/pages/InsightsInterface.tsx +++ b/src/frontend/pages/InsightsInterface.tsx @@ -315,10 +315,8 @@ function InsightsInterface({ userId }: InsightsInterfaceProps) { {/* Main Content */} - {/* Header */} @@ -496,7 +494,7 @@ function InsightsInterface({ userId }: InsightsInterfaceProps) { {/* Bottom Header */} 0} /> - + ); } diff --git a/src/frontend/pages/Settings.tsx b/src/frontend/pages/Settings.tsx index ff28c3c..bb7e353 100644 --- a/src/frontend/pages/Settings.tsx +++ b/src/frontend/pages/Settings.tsx @@ -1,5 +1,4 @@ import { useRef, useState, useEffect } from 'react'; -import { motion } from 'framer-motion'; import Header from '../components/Header'; import SettingItem from '../ui/setting-item'; import ToggleSwitch from '../ui/toggle-switch'; @@ -86,12 +85,9 @@ function Settings({ onBack, isDarkMode, onToggleDarkMode, userId }: SettingsProp
{/* Settings Content */} -

Mentra Merge v1.0.0

-
+ ); } diff --git a/src/server/mastra/agents/initial-agent.ts b/src/server/mastra/agents/initial-agent.ts index 86c1ccc..485aedb 100644 --- a/src/server/mastra/agents/initial-agent.ts +++ b/src/server/mastra/agents/initial-agent.ts @@ -6,6 +6,14 @@ const baseInstructions = `You are the Initial Agent for Merge, a proactive conve **Core Directive: Your #1 rule is to never provide a response that is not majority new information. You should add new, extremely insightful, substantive value. You are a silent observer whose ONLY purpose is to provide highly elevating insights that introduce a significantly important new fact, a "why," or a "how." You must NEVER merely rephrase, summarize, or confirm what was just said. If you cannot add significant new information, you MUST remain SILENT. You are not a participant and are never spoken to directly.** +--- LANGUAGE RULES (HIGHEST PRIORITY) --- +You MUST detect the language being spoken in the conversation and respond in that SAME language. +- If the user is speaking French, ALL your outputs (insights, definitions, fact-checks) MUST be in French. +- If the user is speaking Spanish, respond in Spanish. Same for any other language. +- This applies to EVERY action type: INSIGHT, ROUTE queries, and all output text. +- **CRITICAL: Do NOT treat foreign-language words as "definable terms."** A French speaker saying "boulangerie" is NOT using jargon — they are speaking French. Only define terms that would be jargon/acronyms WITHIN the language being spoken (e.g., a French speaker saying "API" or "machine learning" — those are technical terms worth defining). +- When routing to specialist agents, formulate queries in the language that will get the best results (usually English for web searches), but your final user-facing output MUST be in the conversation's language. + --- HIGHEST PRIORITY: Respond to All Information-Seeking --- Your absolute first priority is to determine if the user is seeking information. This can be a direct question or an indirect statement of curiosity. If you detect an information-seeking statement, you MUST provide an answer or perform the necessary action (like a web search). This rule overrides all other rules and frequency settings. diff --git a/src/server/mastra/agents/specialist-agents.ts b/src/server/mastra/agents/specialist-agents.ts index d1c31ab..00415e8 100644 --- a/src/server/mastra/agents/specialist-agents.ts +++ b/src/server/mastra/agents/specialist-agents.ts @@ -18,43 +18,51 @@ export const definerAgent = new Agent({ model: openai("gpt-4.1-mini"), instructions: `You are a specialist agent that defines acronyms and technical terms. -INPUT: You receive a technical term, acronym, or jargon that needs definition. +INPUT: You receive a technical term, acronym, or jargon that needs definition. You may also receive a language hint indicating what language the user is speaking. + +LANGUAGE RULE: You MUST respond in the same language the user is speaking. If the conversation is in French, define terms in French. If in Spanish, define in Spanish. Only the term itself stays in its original form — the definition must be in the user's language. OUTPUT REQUIREMENTS: -- Format: "TERM: Definition" (e.g., "ASR: Automatic Speech Recognition") +- Format: "TERM: Definition" (e.g., "ASR: Automatic Speech Recognition", or in French: "ASR: Reconnaissance automatique de la parole") - Maximum 60 characters (about 10 words) -- Only define technical/professional terms, not common words +- Only define technical/professional terms, not common words in the user's language - Use standard expansions for acronyms -- Avoid unnecessary words like "a", "the" when space is tight +- Avoid unnecessary words when space is tight -EXAMPLES: +EXAMPLES (English): - "API: Application Programming Interface" - "ML: Machine Learning" -- "CRUD: Create Read Update Delete" -- "OAuth: Open Authorization" -- "IoT: Internet of Things"` + +EXAMPLES (French): +- "API: Interface de programmation" +- "ML: Apprentissage automatique"` }); // FactChecker Agent - for verifying claims export const factCheckerAgent = new Agent({ name: "FactCheckerAgent", model: openai("gpt-4.1-mini"), - instructions: `You are a fact-checking specialist for smart glasses that clarifies false statements. You must start your response with "False: " and then provide the correct fact. + instructions: `You are a fact-checking specialist for smart glasses that clarifies false statements. You must start your response with "False: " (or the equivalent in the user's language, e.g., "Faux: " in French) and then provide the correct fact. + +LANGUAGE RULE: You MUST respond in the same language the user is speaking. If the conversation is in French, respond in French. If in Spanish, respond in Spanish. INPUT: Claims or statements that need verification. OUTPUT REQUIREMENTS: -- Format MUST follow this exact format: "False: [correct fact]" +- Format MUST follow this exact format: "False: [correct fact]" (or localized equivalent) - Maximum 60 characters - Include the most important correction - Use percentages, numbers, dates when relevant - Focus on facts that impact decisions -EXAMPLES: +EXAMPLES (English): - "False: Android has 70% global share" -- "False: Vaccine-autism link disproven" - "False: Napoleon was short (average height)" +EXAMPLES (French): +- "Faux: Android a 70% de part mondiale" +- "Faux: Napoléon était de taille moyenne" + PRIORITIES: 1. Health/safety misinformation 2. Financial/business facts @@ -135,6 +143,8 @@ EXAMPLES: - Query: "Weather in SF" → "68°F Foggy" - Query: "Lakers score" → "Lakers beat Celtics 110-95" +LANGUAGE RULE: If the user's original query was in a non-English language (French, Spanish, etc.), your synthesized output MUST be in that same language. Search results may be in English — translate your final output to match the user's language. + Your only job is to synthesize the provided data into useful insights.`, tools: { serpApiSearchTool } }); @@ -151,7 +161,8 @@ Analyze the user's original query to understand their specific intent and follow - If the user asks about a single, specific place, focus only on that result but ensure you state its distance. - If the user asks for general recommendations ("where should I eat," "good food"), list the top 2-3 most relevant results, mentioning their rating and distance. - Keep your response conversational and directly answer the user's question. -- **IMPORTANT: Your final response MUST be under 15 words.**`, +- **IMPORTANT: Your final response MUST be under 15 words.** +- **LANGUAGE RULE:** Respond in the same language as the user's original query. If the query is in French, respond in French.`, }); export const weatherAgent = new Agent({ @@ -163,7 +174,8 @@ export const weatherAgent = new Agent({ - Always provide the temperature in Fahrenheit. - Format the response like: "It's 75°F and Sunny." or "75°F, Clear skies." for the user's current location. - If the query was for a specific location, format it as: "It's 88°F and Sunny in Miami." -- Keep your response under 15 words.`, +- Keep your response under 15 words. +- **LANGUAGE RULE:** Respond in the same language as the user's original query. If the query is in French, respond in French.`, }); // Computation Agent - for calculations @@ -231,7 +243,8 @@ OUTPUT: Format results for smart glasses display: - Keep under 60 characters total - Use | to separate multiple results - Add % for percentages when appropriate -- Round to reasonable precision (2-4 decimal places max)`, +- Round to reasonable precision (2-4 decimal places max) +- **LANGUAGE RULE:** If context indicates the user speaks a non-English language, format labels in that language (e.g., "Pourboire: 13,50 $" instead of "Tip: $13.50").`, tools: { calculationTool } });