Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.git
.next
node_modules
release
dist

.env
.env.*
!.env.example

*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

Dockerfile
docker-compose*.yml
121 changes: 121 additions & 0 deletions .github/workflows/desktop-packaging.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
name: Desktop Packaging

on:
workflow_dispatch:
push:
branches:
- "codex/**"
paths:
- ".github/workflows/desktop-packaging.yml"
- ".gitmodules"
- "afterPack.js"
- "build/**"
- "electron/**"
- "package-lock.json"
- "package.json"
- "packages/studio/**"
- "packages/Vibe-Workflow"
- "src/desktop/**"
- "vite.config.mjs"
pull_request:
paths:
- ".github/workflows/desktop-packaging.yml"
- ".gitmodules"
- "afterPack.js"
- "build/**"
- "electron/**"
- "package-lock.json"
- "package.json"
- "packages/studio/**"
- "packages/Vibe-Workflow"
- "src/desktop/**"
- "vite.config.mjs"

jobs:
linux:
name: Linux AppImage and DEB
runs-on: ubuntu-24.04
steps:
- name: Check out repository
uses: actions/checkout@v5
with:
submodules: recursive

- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: npm

- name: Install system smoke-test dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
binutils \
file \
xvfb \
xauth \
libgtk-3-0 \
libnotify4 \
libnss3 \
libxss1 \
libxtst6 \
xdg-utils \
libatspi2.0-0 \
libuuid1 \
libsecret-1-0 \
libasound2t64 \
libgbm1

- name: Install dependencies
run: npm ci

- name: Build Linux packages
run: npm run electron:build:linux:ci

- name: Inspect package metadata
run: |
file release/MozenAIGC-*.AppImage
file release/open-generative-ai_*_amd64.deb
dpkg-deb --field release/open-generative-ai_*_amd64.deb Package Version Architecture Maintainer
dpkg-deb --contents release/open-generative-ai_*_amd64.deb | grep -E 'apparmor.profile|MozenAIGC.desktop|/opt/MozenAIGC/open-generative-ai'

- name: Smoke test AppImage
run: |
chmod +x release/MozenAIGC-*.AppImage
set +e
APPIMAGE_EXTRACT_AND_RUN=1 timeout --kill-after=5s 25s xvfb-run -a release/MozenAIGC-*.AppImage --no-sandbox > /tmp/mozen-appimage-smoke.log 2>&1
status=$?
set -e
tail -n 120 /tmp/mozen-appimage-smoke.log
if [ "$status" != "0" ] && [ "$status" != "124" ]; then
exit "$status"
fi

- name: Smoke test DEB install
run: |
sudo apt-get install -y --no-install-recommends ./release/open-generative-ai_*_amd64.deb
test -x /opt/MozenAIGC/open-generative-ai
test -f /opt/MozenAIGC/resources/apparmor.profile
set +e
timeout --kill-after=5s 25s xvfb-run -a /opt/MozenAIGC/open-generative-ai --no-sandbox > /tmp/mozen-deb-smoke.log 2>&1
status=$?
set -e
tail -n 120 /tmp/mozen-deb-smoke.log
if [ "$status" != "0" ] && [ "$status" != "124" ]; then
exit "$status"
fi

- name: Audit packaged artifacts for secrets
run: npm run test:secrets-audit

- name: Upload Linux artifacts
uses: actions/upload-artifact@v6
with:
name: desktop-linux
path: |
release/*.AppImage
release/*.deb
release/latest-linux.yml
release/linux-unpacked/resources/apparmor.profile
if-no-files-found: error
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dist-ssr

# Electron build output
release/
release-linux-docker/
.webpack/

# Next.js
Expand Down
571 changes: 268 additions & 303 deletions README.md

Large diffs are not rendered by default.

96 changes: 85 additions & 11 deletions app/agents/[agent_id]/AgentChatClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,58 @@
import { AiAgent } from "ai-agent";
import "ai-agent/dist/tailwind.css";
import { useCallback, useEffect, useRef } from "react";
import { useRouter } from "next/navigation";
import axios from "axios";
import {
API_PROVIDER_STORAGE_KEY,
buildProviderRequestHeaders,
getActiveProvider,
normalizeApiConfig,
normalizeApiKey,
} from "studio";

const STORAGE_KEY = "muapi_key";
const LEGACY_STORAGE_KEY = "muapi_key";

function getCookieValue(name) {
if (typeof document === "undefined") return null;
const match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));
if (!match) return null;
try {
return decodeURIComponent(match[1]);
} catch {
return match[1];
}
}

function readProviderContext() {
if (typeof window === "undefined") return { apiKey: null, headers: {} };

let storedConfig = null;
try {
const raw = localStorage.getItem(API_PROVIDER_STORAGE_KEY);
storedConfig = raw ? JSON.parse(raw) : null;
} catch {
storedConfig = null;
}

const legacyKey = normalizeApiKey(localStorage.getItem(LEGACY_STORAGE_KEY));
const apiConfig = normalizeApiConfig(storedConfig, legacyKey || getCookieValue("provider_api_key"));
const activeProvider = getActiveProvider(apiConfig);
const apiKey =
normalizeApiKey(activeProvider.apiKey) ||
normalizeApiKey(getCookieValue("provider_api_key")) ||
normalizeApiKey(getCookieValue("yunwu_api_key")) ||
legacyKey ||
normalizeApiKey(getCookieValue(LEGACY_STORAGE_KEY));

return {
apiKey,
headers: {
...buildProviderRequestHeaders(apiConfig),
...(apiKey ? { "x-api-key": apiKey, Authorization: `Bearer ${apiKey}` } : {}),
},
};
}

/**
* AgentChatClient — mirrors muapiapp's AgentClient.js.
Expand All @@ -18,6 +67,7 @@ const STORAGE_KEY = "muapi_key";
*/
export default function AgentChatClient({ agentDetails, initialHistory, userData }) {
const interceptorRef = useRef(null);
const router = useRouter();

console.log("[AgentChatClient] Rendering", {
hasAgentDetails: !!agentDetails,
Expand All @@ -26,15 +76,8 @@ export default function AgentChatClient({ agentDetails, initialHistory, userData
});

useEffect(() => {
const getKey = () => {
if (typeof window === "undefined") return null;
const fromStorage = localStorage.getItem(STORAGE_KEY);
if (fromStorage) return fromStorage;
const match = document.cookie.match(/muapi_key=([^;]+)/);
return match ? match[1] : null;
};

const apiKey = getKey();
const providerContext = readProviderContext();
const apiKey = providerContext.apiKey;
if (!apiKey) return;

interceptorRef.current = axios.interceptors.request.use((config) => {
Expand All @@ -44,7 +87,10 @@ export default function AgentChatClient({ agentDetails, initialHistory, userData
const isInternalProxy = config.url.includes('/api/app') || config.url.includes('/api/workflow') || config.url.includes('/api/agents') || config.url.includes('/api/api') || config.url.includes('/api/v1');

if (isRelative || isInternalProxy) {
config.headers["x-api-key"] = apiKey;
config.headers = {
...config.headers,
...providerContext.headers,
};
}
return config;
});
Expand All @@ -70,6 +116,34 @@ export default function AgentChatClient({ agentDetails, initialHistory, userData
[userData]
);

if (!agentDetails) {
return (
<div className="h-screen w-full bg-[#030303] text-white flex items-center justify-center p-8">
<div className="w-full max-w-md border border-white/10 bg-white/[0.03] rounded-2xl p-8 text-center shadow-2xl">
<div className="w-12 h-12 mx-auto mb-5 rounded-xl bg-[#d9ff00]/10 border border-[#d9ff00]/20 flex items-center justify-center text-[#d9ff00]">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
<rect x="3" y="11" width="18" height="10" rx="2" />
<path d="M7 11V7a5 5 0 0110 0v4" />
</svg>
</div>
<h1 className="text-sm font-black uppercase tracking-[0.2em] mb-3">
智能体详情加载失败
</h1>
<p className="text-sm leading-relaxed text-white/45 mb-6">
打开智能体对话需要有效的当前 API 通道。请回到工作台,在 API 管理中保存密钥后再进入。
</p>
<button
type="button"
onClick={() => router.push("/studio/agents")}
className="px-5 py-2.5 rounded-lg bg-[#d9ff00] text-black text-xs font-black uppercase tracking-widest hover:bg-white transition-colors"
>
返回智能体
</button>
</div>
</div>
);
}

return (
<div className="h-screen w-full bg-black">
<AiAgent
Expand Down
Loading