Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions examples/sites/.stylelintrc.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
module.exports = {
extends: 'stylelint-config-standard', //stylelint-config-airbnb
extends: 'stylelint-config-standard',
rules: {
'string-quotes': 'single',
'property-no-unknown': true,
'selector-pseudo-class-no-unknown': true,
'at-rule-empty-line-before': 'always',
'block-no-empty': true,
'indentation': 4 // http://cui.ulanqab.huawei.com/#/articalDetail?id=b76da810d8ed8
'indentation': 4
}
}
3 changes: 3 additions & 0 deletions examples/sites/env/.env
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ VITE_APP_MODE='pc'

VITE_APP_BUILD_BASE_URL='/'
VITE_PLAYGROUND_URL=/playground.html

VITE_LLM_API_KEY=
VITE_LLM_URL=https://api.deepseek.com/v1
Comment on lines +9 to +11
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Externalise secrets to avoid accidental leakage

Committing real VITE_LLM_API_KEY values directly (or even an empty placeholder in a committed .env) makes it too easy for a future commit to leak credentials.
Recommend:

  1. Commit a .env.example containing only place-holders.
  2. Add .env to .gitignore so that real keys remain local.

This small discipline prevents credential exposure in OSS projects.

🤖 Prompt for AI Agents
In examples/sites/env/.env around lines 9 to 11, the real or placeholder API key
is committed directly, risking accidental credential leaks. To fix this, remove
the actual key from this file, commit a separate .env.example file with only
placeholder values, and add .env to .gitignore so that real secret keys are
never committed to the repository.

7 changes: 6 additions & 1 deletion examples/sites/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
"@docsearch/css": "^3.8.0",
"@docsearch/js": "^3.8.0",
"@docsearch/react": "npm:@docsearch/css",
"@opentiny/next-sdk": "0.0.1-alpha.5",
"@opentiny/tiny-robot": "0.3.0-alpha.3",
"@opentiny/tiny-robot-kit": "0.3.0-alpha.3",
"@opentiny/tiny-robot-svgs": "0.3.0-alpha.3",
Comment on lines +30 to +33
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify alpha version stability and security for production use.

These alpha versions (@opentiny/next-sdk at 0.0.1-alpha.5 and @opentiny/tiny-robot packages at 0.3.0-alpha.3) may introduce instability in production environments. Alpha releases typically have incomplete features and potential breaking changes.


🏁 Script executed:

#!/bin/bash
# Check for security advisories and release stability of the new packages
echo "Checking security advisories for new packages..."

for package in "@opentiny/next-sdk" "@opentiny/tiny-robot" "@opentiny/tiny-robot-kit" "@opentiny/tiny-robot-svgs"; do
  echo "Checking $package..."
  npm audit --package-lock-only --audit-level moderate 2>/dev/null | grep -i "$package" || echo "No advisories found for $package"
done

# Check npm registry for latest versions
echo -e "\nChecking latest versions..."
npm view @opentiny/next-sdk versions --json | tail -10
npm view @opentiny/tiny-robot versions --json | tail -10

Length of output: 3009


Upgrade alpha dependencies for stability and production readiness

No security advisories were found for these packages, but you’re locked to very early alpha versions:

  • examples/sites/package.json (lines 30–33)
    • @opentiny/next-sdk remains at 0.0.1-alpha.5 (latest)
    • @opentiny/tiny-robot, @opentiny/tiny-robot-kit, and @opentiny/tiny-robot-svgs are pinned at 0.3.0-alpha.3, while the latest available is 0.3.0-alpha.14.

Please update these entries to receive the latest fixes or consider waiting for a stable release:

- "@opentiny/tiny-robot": "0.3.0-alpha.3",
- "@opentiny/tiny-robot-kit": "0.3.0-alpha.3",
- "@opentiny/tiny-robot-svgs": "0.3.0-alpha.3",
+ "@opentiny/tiny-robot": "0.3.0-alpha.14",
+ "@opentiny/tiny-robot-kit": "0.3.0-alpha.14",
+ "@opentiny/tiny-robot-svgs": "0.3.0-alpha.14",

Optionally use caret ranges (e.g. "^0.3.0-alpha.14") if you want to track future alpha updates automatically. Confirm that alpha-level dependencies align with your stability and security requirements before deploying to production.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"@opentiny/next-sdk": "0.0.1-alpha.5",
"@opentiny/tiny-robot": "0.3.0-alpha.3",
"@opentiny/tiny-robot-kit": "0.3.0-alpha.3",
"@opentiny/tiny-robot-svgs": "0.3.0-alpha.3",
"@opentiny/next-sdk": "0.0.1-alpha.5",
"@opentiny/tiny-robot": "0.3.0-alpha.14",
"@opentiny/tiny-robot-kit": "0.3.0-alpha.14",
"@opentiny/tiny-robot-svgs": "0.3.0-alpha.14",
🤖 Prompt for AI Agents
In examples/sites/package.json around lines 30 to 33, the dependencies
@opentiny/tiny-robot, @opentiny/tiny-robot-kit, and @opentiny/tiny-robot-svgs
are pinned to older alpha versions 0.3.0-alpha.3, while newer alpha versions
0.3.0-alpha.14 are available. Update these dependencies to the latest alpha
versions by changing their version strings to "0.3.0-alpha.14" or use caret
ranges like "^0.3.0-alpha.14" to track future alpha updates automatically. Also
consider updating @opentiny/next-sdk if a newer alpha is available or confirm it
is at the latest. Ensure these changes align with your stability and security
requirements before deploying.

"@opentiny/tiny-vue-mcp": "^0.0.2",
"@opentiny/utils": "workspace:~",
"@opentiny/vue": "workspace:~",
Expand Down Expand Up @@ -62,7 +66,8 @@
"tailwindcss": "^3.2.4",
"vue": "^3.4.31",
"vue-i18n": "~9.14.3",
"vue-router": "4.1.5"
"vue-router": "4.1.5",
"zod": "^3.24.4"
},
"devDependencies": {
"@opentiny-internal/unplugin-virtual-template": "workspace:~",
Expand Down
159 changes: 118 additions & 41 deletions examples/sites/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,120 @@
<iframe v-if="modalSHow" width="100%" height="100%" :src="previewUrl" frameborder="0"></iframe>
</tiny-modal>
</tiny-config-provider>
<div class="right-panel" :class="{ collapsed: !showTinyRobot }">
<tiny-robot-chat />
</div>
<IconAi @click="handleShowTinyRobot" class="style-settings-icon"></IconAi>
<tiny-dialog-box
v-model:visible="boxVisibility"
:close-on-click-modal="false"
title="请填写您的LLM信息, 否则无法体验智能化能力"
width="30%"
>
<div>
<tiny-form ref="formRef" :model="createData" label-width="120px">
<tiny-form-item label="LLM URL" prop="llmUrl" :rules="{ required: true, messages: '必填', trigger: 'blur' }">
<tiny-input v-model="createData.llmUrl"></tiny-input>
</tiny-form-item>
<tiny-form-item
label="API Key"
prop="llmApiKey"
:rules="{ required: true, messages: '必填', trigger: 'blur' }"
>
<tiny-input v-model="createData.llmApiKey"></tiny-input>
</tiny-form-item>
<tiny-form-item>
<tiny-button @click="submit" type="primary">保存</tiny-button>
</tiny-form-item>
</tiny-form>
</div>
</tiny-dialog-box>
</div>
</template>

<script>
import { defineComponent, onMounted, provide, ref } from 'vue'
import { ConfigProvider, Modal } from '@opentiny/vue'
import { iconClose } from '@opentiny/vue-icon'
import { appData } from './tools'
<script setup lang="ts">
import { onMounted, provide, ref, reactive } from 'vue'
import {
TinyConfigProvider,
TinyModal,
TinyDialogBox,
TinyForm,
TinyFormItem,
TinyInput,
TinyButton
} from '@opentiny/vue'
import useTheme from './tools/useTheme'
import TinyRobotChat from './components/tiny-robot-chat.vue'
import { IconAi } from '@opentiny/tiny-robot-svgs'
import { showTinyRobot } from './composable/utils'
import { createServer, createInMemoryTransport } from '@opentiny/next-sdk'
import { createGlobalMcpTool } from './tools/globalMcpTool'
import { $local, isEnvLLMDefined, isLocalLLMDefined } from './composable/utils'

export default defineComponent({
name: 'AppVue',
props: [],
components: {
TinyConfigProvider: ConfigProvider,
TinyModal: Modal,
TinyIconClose: iconClose()
},
setup() {
const previewUrl = ref(import.meta.env.VITE_PLAYGROUND_URL)
const modalSHow = ref(false)
const boxVisibility = ref(false)
const formRef = ref()
const createData = reactive({
llmUrl: $local.llmUrl || import.meta.env.VITE_LLM_URL,
llmApiKey: $local.llmApiKey || import.meta.env.VITE_LLM_API_KEY
})

onMounted(() => {
// 加载header
const common = new window.TDCommon(['#header'], {
allowDarkTheme: true,
searchConfig: {
show: true
},
menuCollapse: {
useCollapse: true, // 启用1024以下隐藏菜单
menuId: '#layoutSider'
}
})
common.renderHeader()
})
const { designConfig, currentThemeKey } = useTheme()
const submit = () => {
formRef.value.validate().then(() => {
$local.llmUrl = createData.llmUrl
$local.llmApiKey = createData.llmApiKey
Comment on lines +69 to +70
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Security: Avoid storing API keys in localStorage

Storing API keys in localStorage is insecure as they can be accessed by any script. Consider using a more secure storage method or implementing a backend proxy.

For production use, API keys should be handled server-side. Consider:

  1. Implementing a backend proxy that stores the API keys securely
  2. Using session storage with encryption
  3. Warning users about the security implications
🤖 Prompt for AI Agents
In examples/sites/src/App.vue around lines 69 to 70, the code stores the API key
in localStorage, which is insecure. To fix this, remove storing the API key in
localStorage and instead implement a backend proxy to handle API requests
securely, or use a more secure storage method such as encrypted session storage.
Additionally, update the code to fetch the API key from the secure backend or
encrypted storage rather than localStorage.

boxVisibility.value = false
window.location.reload()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid using window.location.reload()

Full page reload disrupts the single-page application experience. Consider using Vue's reactivity to update the necessary components.

-    window.location.reload()
+    // Emit an event or use a reactive store to notify components about the configuration change
+    showTinyRobot.value = true
+    // Re-initialize the AI client with new credentials

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In examples/sites/src/App.vue at line 72, replace the use of
window.location.reload() with Vue's reactive state management to update the
necessary components without a full page reload. Identify the specific data or
state changes needed and trigger those updates through Vue's reactive properties
or methods to maintain the single-page application experience.

})
}

provide('showPreview', (url) => {
previewUrl.value = url
modalSHow.value = true
})
return {
appData,
designConfig,
currentThemeKey,
previewUrl,
modalSHow
const previewUrl = ref(import.meta.env.VITE_PLAYGROUND_URL)
const modalSHow = ref(false)
const server = createServer(
{
name: 'comprehensive-config',
version: '1.0.0'
},
{
capabilities: {
logging: {},
resources: { subscribe: true, listChanged: true }
}
}
)

server.use(createInMemoryTransport())

createGlobalMcpTool(server)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Pass router instance to createGlobalMcpTool

Based on the earlier review of globalMcpTool.ts, this function needs a router instance.

+import { useRouter } from 'vue-router'
+
+const router = useRouter()
-createGlobalMcpTool(server)
+createGlobalMcpTool(server, router)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
createGlobalMcpTool(server)
import { useRouter } from 'vue-router'
const router = useRouter()
createGlobalMcpTool(server, router)
🤖 Prompt for AI Agents
In examples/sites/src/App.vue at line 93, the call to createGlobalMcpTool is
missing the required router instance argument. Modify the call to pass the
router instance as an argument to createGlobalMcpTool, ensuring it receives the
router it needs to function correctly.


onMounted(() => {
server.connectTransport()
// 加载header
Comment on lines +78 to +97
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for server initialization

Server creation and connection could fail. Add try-catch blocks to handle potential errors gracefully.

+try {
   const server = createServer(
     // ... server config ...
   )
   
   server.use(createInMemoryTransport())
   
   createGlobalMcpTool(server, router)
   
   onMounted(() => {
-    server.connectTransport()
+    try {
+      server.connectTransport()
+    } catch (error) {
+      console.error('Failed to connect server transport:', error)
+    }
     // ... rest of onMounted code ...
   })
+} catch (error) {
+  console.error('Failed to initialize server:', error)
+}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In examples/sites/src/App.vue around lines 78 to 97, the server creation and
connection code lacks error handling. Wrap the server creation and the
server.connectTransport() call inside try-catch blocks to catch any exceptions.
In the catch block, log or handle the error gracefully to prevent the app from
crashing unexpectedly.

const common = new window.TDCommon(['#header'], {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add type checking for window.TDCommon

Using window.TDCommon without type checking could cause runtime errors if the script hasn't loaded.

-  const common = new window.TDCommon(['#header'], {
+  if (typeof window.TDCommon === 'undefined') {
+    console.error('TDCommon is not loaded')
+    return
+  }
+  const common = new window.TDCommon(['#header'], {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const common = new window.TDCommon(['#header'], {
if (typeof window.TDCommon === 'undefined') {
console.error('TDCommon is not loaded')
return
}
const common = new window.TDCommon(['#header'], {
🤖 Prompt for AI Agents
In examples/sites/src/App.vue at line 98, add a type check before using
window.TDCommon to ensure it is defined and loaded. Wrap the usage of
window.TDCommon in a conditional statement that verifies its existence to
prevent runtime errors if the script hasn't loaded yet.

allowDarkTheme: true,
searchConfig: {
show: true
},
menuCollapse: {
useCollapse: true, // 启用1024以下隐藏菜单
menuId: '#layoutSider'
}
})
common.renderHeader()
})
const { designConfig, currentThemeKey } = useTheme()

provide('showPreview', (url) => {
previewUrl.value = url
modalSHow.value = true
})

const handleShowTinyRobot = () => {
if (!isEnvLLMDefined && !isLocalLLMDefined) {
boxVisibility.value = true
} else {
showTinyRobot.value = !showTinyRobot.value
}
}
</script>

<style scoped lang="less">
Expand All @@ -73,4 +136,18 @@ export default defineComponent({
padding: 34px 0 0;
}
}
.right-panel {
:deep(.tr-container) {
z-index: 9999;
}
}

.style-settings-icon {
position: fixed;
bottom: 100px;
right: 100px;
font-size: 24px;
z-index: 19999;
cursor: pointer;
}
</style>
12 changes: 12 additions & 0 deletions examples/sites/src/components/ReactiveMarkdown.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<template>
<div v-html="markdown"></div>
</template>

<script setup lang="ts">
import { BubbleMarkdownMessageRenderer } from '@opentiny/tiny-robot'
import { computed } from 'vue'

const props = defineProps<{ content: string }>()
const markdownRenderer = new BubbleMarkdownMessageRenderer()
const markdown = computed(() => markdownRenderer.md.render(props.content))
</script>
Loading
Loading