├── .gitignore ├── .npmrc ├── .prettierrc.cjs ├── .vscode └── extensions.json ├── LICENSE ├── README.md ├── examples ├── .gitignore ├── README.md ├── index.html ├── package.json ├── public │ └── vite.svg ├── src │ ├── App.vue │ ├── assets │ │ └── vue.svg │ ├── components │ │ ├── ProvideApiKeyDialog.tsx │ │ └── TodoItem.vue │ ├── hooks │ │ └── utils.ts │ ├── lib │ │ └── email-history.json │ ├── main.ts │ ├── pages │ │ ├── form.vue │ │ ├── index.vue │ │ ├── presentation.vue │ │ ├── spreadsheet.vue │ │ ├── table.tsx │ │ ├── textarea.vue │ │ └── todolist.vue │ ├── router │ │ └── index.ts │ ├── style.css │ └── vite-env.d.ts ├── tsconfig.json └── vite.config.ts ├── lerna.json ├── package.json ├── packages ├── vite-config │ ├── package.json │ ├── src │ │ └── index.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── vue-core │ ├── .autocodercommands │ │ └── hello.md │ ├── .autocoderignore │ ├── .gitignore │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── copilotkit-props.ts │ │ │ ├── copilotkit.tsx │ │ │ └── index.ts │ │ ├── context │ │ │ ├── copilot-context.ts │ │ │ └── index.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── use-chat.ts │ │ │ ├── use-copilot-action.ts │ │ │ ├── use-copilot-chat.ts │ │ │ ├── use-copilot-readable.ts │ │ │ ├── use-flat-category-store.ts │ │ │ ├── use-make-copilot-document-readable.ts │ │ │ └── use-tree.ts │ │ ├── index.ts │ │ └── types │ │ │ ├── chat-suggestion-configuration.ts │ │ │ ├── document-pointer.ts │ │ │ ├── frontend-action.ts │ │ │ ├── index.ts │ │ │ └── system-message.ts │ ├── tsconfig.json │ └── vite.config.ts ├── vue-textarea │ ├── README.md │ ├── auto-imports.d.ts │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── base-copilot-textarea │ │ │ │ ├── base-copilot-textarea.css │ │ │ │ ├── base-copilot-textarea.tsx │ │ │ │ ├── use-add-branding-css.tsx │ │ │ │ └── use-add-placeholder-css.tsx │ │ │ ├── copilot-textarea │ │ │ │ └── copilot-textarea.tsx │ │ │ ├── hovering-toolbar │ │ │ │ ├── hovering-editor-provider.tsx │ │ │ │ ├── hovering-toolbar.tsx │ │ │ │ └── text-insertion-prompt-box │ │ │ │ │ ├── hovering-insertion-prompt-box-core.tsx │ │ │ │ │ ├── hovering-insertion-prompt-box.tsx │ │ │ │ │ ├── included-files-preview.tsx │ │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ └── source-search-box │ │ │ │ └── source-search-box.tsx │ │ ├── css │ │ │ ├── baseTextarea.css │ │ │ └── tailwind.css │ │ ├── hooks │ │ │ ├── base-copilot-textarea-implementation │ │ │ │ ├── use-autosuggestions.ts │ │ │ │ └── use-copilot-textarea-editor.tsx │ │ │ ├── index.ts │ │ │ ├── make-autosuggestions-function │ │ │ │ ├── use-make-standard-autosuggestions-function.tsx │ │ │ │ └── use-make-standard-insertion-function.tsx │ │ │ ├── misc │ │ │ │ └── use-autosize-textarea.tsx │ │ │ └── track-cursor-moved-since-last-text-change.ts │ │ ├── index.ts │ │ ├── lib │ │ │ ├── debouncer.ts │ │ │ ├── editor-to-text.ts │ │ │ ├── get-text-around-cursor.ts │ │ │ ├── retry.tsx │ │ │ ├── stream-promise-flatten.ts │ │ │ ├── tiptap-edits │ │ │ │ ├── add-autocompletions.tsx │ │ │ │ ├── clear-autocompletions.tsx │ │ │ │ └── replace-text.ts │ │ │ └── utils.ts │ │ ├── styles.css │ │ └── types │ │ │ ├── autosuggestions-config │ │ │ ├── autosuggestions-config-user-specified.tsx │ │ │ ├── autosuggestions-config.tsx │ │ │ ├── editing-api-config.tsx │ │ │ ├── index.ts │ │ │ ├── insertions-api-config.tsx │ │ │ ├── subtypes │ │ │ │ └── make-system-prompt.ts │ │ │ └── suggestions-api-config.tsx │ │ │ ├── base │ │ │ ├── autosuggestion-state.ts │ │ │ ├── autosuggestions-bare-function.ts │ │ │ ├── base-autosuggestions-config.tsx │ │ │ ├── base-copilot-textarea-props.tsx │ │ │ ├── editor-autocomplete-state.ts │ │ │ └── index.ts │ │ │ ├── html-copilot-textarea-element.ts │ │ │ └── index.ts │ ├── tsconfig.json │ └── vite.config.ts └── vue-ui │ ├── package.json │ ├── src │ ├── components │ │ ├── chat │ │ │ ├── Button.tsx │ │ │ ├── Chat.tsx │ │ │ ├── ChatContext.tsx │ │ │ ├── Header.tsx │ │ │ ├── Icon.tsx │ │ │ ├── Input.tsx │ │ │ ├── Markdown.tsx │ │ │ ├── Messages.tsx │ │ │ ├── Modal.tsx │ │ │ ├── Popup.tsx │ │ │ ├── Response.tsx │ │ │ ├── Sidebar.tsx │ │ │ ├── Suggestion.tsx │ │ │ ├── Textarea.tsx │ │ │ ├── Window.tsx │ │ │ └── props.ts │ │ └── index.ts │ ├── css │ │ ├── animations.css │ │ ├── button.css │ │ ├── chat.css │ │ ├── colors.css │ │ ├── header.css │ │ ├── input.css │ │ ├── markdown.css │ │ ├── messages.css │ │ ├── popup.css │ │ ├── response.css │ │ ├── sidebar.css │ │ ├── suggestions.css │ │ └── window.css │ ├── index.ts │ ├── styles.css │ └── types │ │ └── suggestions.ts │ ├── tsconfig.json │ └── vite.config.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── tsconfig.json └── turbo.json /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | 11 | # next.js 12 | .next/ 13 | out/ 14 | build 15 | .swc/ 16 | 17 | # misc 18 | .DS_Store 19 | *.pem 20 | 21 | # debug 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # local env files 27 | .env.local 28 | .env.development.local 29 | .env.test.local 30 | .env.production.local 31 | 32 | # turbo 33 | .turbo 34 | 35 | # ui 36 | dist/ 37 | 38 | TODO.local.md 39 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers = true 2 | -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // 每一行代码允许的字符数 3 | printWidth: 120, 4 | // 指定每行缩进的空格数 5 | tabWidth: 2, 6 | // 结尾不带分号 7 | semi: false, 8 | // 使用单引号 9 | singleQuote: true, 10 | // 关闭尾逗号 11 | trailingComma: 'none', 12 | // 指定 HTML 文件的全局空白区域敏感度 13 | htmlWhitespaceSensitivity: 'ignore', 14 | // always 始终保留括号,avoid 不保留括号 15 | arrowParens: 'avoid' 16 | } 17 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar"] 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 fe-51shebao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-copilotkit 2 | #### Implement a Vue version based on the React UI library of copilotkit 3 | #### Welcome to use vue-copilotkit and submit issues. 4 | ## Future possible improvements: 5 | ### 1. keep update with copilotkit 6 | ### 2. Simpler integration, just enter the URL to connect to ollama, xinference, etc. Models can be switched. 7 | ### 3. Support some combination functions of the chat window, refer to open-webui, cursor. 8 | 9 | 基于copilotkit的react UI库实现一个vue版 10 | 11 | 欢迎各位提issue。 12 | 13 | ## 未来可能改进方向: 14 | ### 1、保持跟上copilotkit的更新节奏 15 | ### 2、接入更简单,输入url即可接入ollama,xinference之类。可切换模型,或者直接用国产大模型的key。(初步解决) 16 | ### 3、支持聊天窗口的一些组合功能,参照open-webui, cursor。 17 | 18 | ## 使用教程相关文档 19 | ## Usage Tutorial Documentation 20 | 演示站点:vue-copilotkit
21 | 借助MoAiStudio不写一行代码,完成页面开发-掘金
22 | 借助MoAiStudio不写一行代码,完成页面开发-csdn
23 | 24 | ![Image](https://github.com/fe-51shebao/.github/raw/main/demo1-ok.gif) 25 | ![Image](https://github.com/fe-51shebao/.github/raw/main/demo3-ok.gif) 26 | ![Image](https://github.com/fe-51shebao/.github/raw/main/demo-form.gif) 27 | ![Image](https://github.com/fe-51shebao/.github/raw/main/demo4.gif) -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + TypeScript + Vite 2 | 3 | This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "examples", 3 | "private": true, 4 | "version": "1.0.2", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-vue": "^5.0.5", 13 | "@vitejs/plugin-vue-jsx": "^4.0.0", 14 | "typescript": "^5.2.2", 15 | "unocss": "^0.62.4", 16 | "vite": "^5.3.4", 17 | "vite-plugin-node-polyfills": "^0.22.0", 18 | "vite-plugin-pages": "^0.32.3" 19 | }, 20 | "dependencies": { 21 | "@copilotkit/runtime-client-gql": "1.3.6", 22 | "@copilotkit/shared": "^1.1.0", 23 | "@copilotkit/vue-core": "^1.0.3", 24 | "@copilotkit/vue-textarea": "^1.0.3", 25 | "@copilotkit/vue-ui": "^1.0.3", 26 | "@element-plus/icons-vue": "^2.3.1", 27 | "element-plus": "^2.7.8", 28 | "vue-router": "^4.4.3" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 20 | -------------------------------------------------------------------------------- /examples/src/assets/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/src/components/ProvideApiKeyDialog.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent, onMounted, ref, reactive } from 'vue' 2 | 3 | export default defineComponent({ 4 | name: 'ProvideApiKeyDialog', 5 | props: { 6 | apiKey: { 7 | type: String, 8 | }, 9 | runtimeUrl:{ 10 | type: String, 11 | } 12 | }, 13 | emits: ['update:apiKey','update:runtimeUrl'], 14 | setup(props, { emit }) { 15 | const showDialog = ref(false) 16 | const setShowDialog = (value: boolean) => { 17 | showDialog.value = value 18 | } 19 | const dialogV = reactive({ 20 | apiKey:props.apiKey, 21 | runtimeUrl:props.runtimeUrl 22 | }) 23 | const handleSubmit = () => { 24 | emit('update:apiKey', dialogV.apiKey) 25 | emit('update:runtimeUrl', dialogV.runtimeUrl) 26 | localStorage.setItem("apiKey",''+dialogV.apiKey) 27 | localStorage.setItem("runtimeUrl",''+dialogV.runtimeUrl) 28 | setShowDialog(false) 29 | } 30 | const handleCancel = () => { 31 | setShowDialog(false) 32 | } 33 | onMounted(() => { 34 | (!props.apiKey&&!props.runtimeUrl) && setShowDialog(true) 35 | }) 36 | return () => ( 37 |
38 |
39 | Copilot Cloud API key is set.{" "} 40 | setShowDialog(true)} 43 | > 44 | Change 45 | 46 | 47 |
48 | Don{"'"}t have an API key?{" "} 49 | 50 | 55 | Sign up for free 56 | 57 | . 58 | 59 |

当采用默认的runtimeUrl='http://47.94.253.214/api/copilotkit/zhipu'时,可以在10.30之前免费使用,额度用完为止(貌似莫名不稳定)

60 |

当设置runtimeUrl='http://47.94.253.214/api/copilotkit'时,需要在apiKey输入通义千问的key自行使用,服务器端只是透传,不存储

61 |

当设置runtimeUrl=''时,需要在apiKey输入copilotkit的publicKey,会连接cloud.copilotkit.ai

62 |
63 |
64 |
65 | 66 | 67 | 72 | 修改 73 | 74 | 79 | 取消 80 | 81 |
82 |
83 |
84 | 85 |
86 | ) 87 | } 88 | }) -------------------------------------------------------------------------------- /examples/src/components/TodoItem.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 50 | 51 | -------------------------------------------------------------------------------- /examples/src/hooks/utils.ts: -------------------------------------------------------------------------------- 1 | import { ref, onMounted, watch, type Ref } from 'vue' 2 | 3 | export function useStateWithLocalStorage(defaultValue: string, key: string): [Ref, (newValue: string) => void] { 4 | const state = ref(defaultValue) 5 | const isFirstRender = ref(true) 6 | 7 | // 在组件挂载时从localStorage中获取值 8 | // onMounted(() => { 9 | if (typeof window !== 'undefined') { 10 | const storagedValue = localStorage.getItem(key) 11 | if (storagedValue) { 12 | try { 13 | state.value = JSON.parse(storagedValue) 14 | } catch {} 15 | } 16 | } 17 | // }) 18 | 19 | // 监听state和key的变化,并更新localStorage 20 | watch( 21 | () => state.value, 22 | () => { 23 | if (typeof window !== 'undefined') { 24 | localStorage.setItem(key, JSON.stringify(state.value)) 25 | } 26 | }, 27 | { immediate: true } 28 | ) 29 | 30 | // 用于更新状态的函数 31 | const setState = (newValue: string) => { 32 | state.value = newValue 33 | } 34 | 35 | return [state, setState] 36 | } 37 | -------------------------------------------------------------------------------- /examples/src/lib/email-history.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "timestamp": "2024-02-12T11:00:00", 4 | "from": "彭于晏 ", 5 | "to": "John Doe ", 6 | "body": "嗨,John,与 SpaceY 的通话结果如何?" 7 | }, 8 | { 9 | "timestamp": "2024-02-14T12:00:00", 10 | "from": "John Doe ", 11 | "to": "彭于晏 ", 12 | "body": "谢谢提醒!SpaceY 的 Albert 很高兴继续。首先,我们将构建他们的登陆页面。" 13 | }, 14 | { 15 | "timestamp": "2024-01-14T14:00:00", 16 | "from": "John Doe ", 17 | "to": "彭于晏 ", 18 | "body": "忘了说了,他们真的很喜欢你提出的技术堆栈。他们还想添加一些 AI 功能。" 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /examples/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import './style.css' 3 | import App from './App.vue' 4 | import router from './router' 5 | 6 | import ElementPlus from 'element-plus' 7 | import 'element-plus/dist/index.css' 8 | import 'virtual:uno.css' 9 | 10 | const app = createApp(App) 11 | 12 | app.use(router) 13 | app.use(ElementPlus) 14 | app.mount('#app') 15 | 16 | function fetch_copilotkit_v1() { 17 | fetch('https://api.copilotkit.ai/copilotkit/v1', { 18 | headers: { 19 | 'content-type': 'application/json', 20 | 'x-copilotcloud-public-api-key': 'ck_pub_b60a29b6afc2283bc9fcf15331510374' 21 | }, 22 | body: '{"operationName":"generateCopilotResponse","query":"mutation generateCopilotResponse($data: GenerateCopilotResponseInput!, $properties: JSONObject) {\\n generateCopilotResponse(data: $data, properties: $properties) {\\n threadId\\n runId\\n ... on CopilotResponse @defer {\\n status {\\n ... on BaseResponseStatus {\\n code\\n __typename\\n }\\n ... on FailedResponseStatus {\\n reason\\n details\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n messages @stream {\\n __typename\\n ... on BaseMessageOutput {\\n id\\n createdAt\\n __typename\\n }\\n ... on BaseMessageOutput @defer {\\n status {\\n ... on SuccessMessageStatus {\\n code\\n __typename\\n }\\n ... on FailedMessageStatus {\\n code\\n reason\\n __typename\\n }\\n ... on PendingMessageStatus {\\n code\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n ... on TextMessageOutput {\\n content @stream\\n role\\n __typename\\n }\\n ... on ActionExecutionMessageOutput {\\n name\\n scope\\n arguments @stream\\n __typename\\n }\\n ... on ResultMessageOutput {\\n result\\n actionExecutionId\\n actionName\\n __typename\\n }\\n }\\n __typename\\n }\\n}","variables":{"data":{"cloud":{},"frontend":{"actions":[{"description":"Adds a task to the todo list","jsonSchema":"{\\"type\\":\\"object\\",\\"properties\\":{\\"title\\":{\\"type\\":\\"string\\",\\"description\\":\\"The title of the task\\"}},\\"required\\":[\\"title\\"]}","name":"addTask"},{"description":"Deletes a task from the todo list","jsonSchema":"{\\"type\\":\\"object\\",\\"properties\\":{\\"id\\":{\\"type\\":\\"number\\",\\"description\\":\\"The id of the task\\"}},\\"required\\":[\\"id\\"]}","name":"deleteTask"},{"description":"Sets the status of a task","jsonSchema":"{\\"type\\":\\"object\\",\\"properties\\":{\\"id\\":{\\"type\\":\\"number\\",\\"description\\":\\"The id of the task\\"},\\"status\\":{\\"type\\":\\"string\\",\\"description\\":\\"The status of the task\\",\\"enum\\":[\\"todo\\",\\"done\\"]}},\\"required\\":[\\"id\\",\\"status\\"]}","name":"setTaskStatus"}]},"messages":[{"createdAt":"2024-08-07T02:35:03.308Z","id":"ck-2f25b060-e854-4d16-a253-afccb27c08fb","textMessage":{"content":"\\nPlease act as an efficient, competent, conscientious, and industrious professional assistant.\\n\\nHelp the user achieve their goals, and you do so in a way that is as efficient as possible, without unnecessary fluff, but also without sacrificing professionalism.\\nAlways be polite and respectful, and prefer brevity over verbosity.\\n\\nThe user has provided you with the following context:\\n```\\n\\n\\n1. The state of the todo list: [{\\"id\\":3,\\"title\\":\\"Prepare presentation slides\\",\\"status\\":\\"todo\\"},{\\"id\\":4,\\"title\\":\\"Send meeting notes email\\",\\"status\\":\\"todo\\"},{\\"id\\":5,\\"title\\":\\"Review Uli\'s pull request\\",\\"status\\":\\"todo\\"},{\\"id\\":1,\\"title\\":\\"Complete project proposal\\",\\"status\\":\\"done\\"},{\\"id\\":2,\\"title\\":\\"Review design mockups\\",\\"status\\":\\"done\\"}]\\n\\n```\\n\\nThey have also provided you with functions you can call to initiate actions on their behalf, or functions you can call to receive more information.\\n\\nPlease assist them as best you can.\\n\\nYou can ask them for clarifying questions if needed, but don\'t be annoying about it. If you can reasonably \'fill in the blanks\' yourself, do so.\\n\\nIf you would like to call a function, call it without saying anything else.\\n","role":"system"}},{"createdAt":"2024-08-07T02:35:03.307Z","id":"ck-ee138760-4156-4837-a4c8-bea0317a13c9","textMessage":{"content":"hello","role":"user"}}],"metadata":{"requestType":"Chat"},"runId":null,"threadId":null},"properties":{}}}', 23 | method: 'POST' 24 | }) 25 | .then(res => { 26 | // 检查是否成功,并且确保响应是流式的 27 | if (!res.ok || !res.body) { 28 | throw new Error('Network response was not ok.') 29 | } 30 | 31 | // 获取ReadableStream 32 | const reader = res.body.getReader() 33 | const stream = new ReadableStream({ 34 | start(controller) { 35 | // 读取流 36 | function read() { 37 | reader 38 | .read() 39 | .then(({ done, value }) => { 40 | if (done) { 41 | // 如果读取完成,则关闭流 42 | controller.close() 43 | return 44 | } 45 | // 获取数据块,并将其放入流中 46 | controller.enqueue(value) 47 | // 读取下一个数据块 48 | read() 49 | }) 50 | .catch(error => { 51 | console.error('Error reading data:', error) 52 | controller.error(error) 53 | }) 54 | } 55 | 56 | read() 57 | } 58 | }) 59 | 60 | // 将ReadableStream转换成Text 61 | return new Response(stream).text() 62 | }) 63 | .then(res => { 64 | console.log(res) 65 | }) 66 | } 67 | 68 | // fetch_copilotkit_v1() 69 | -------------------------------------------------------------------------------- /examples/src/pages/form.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 141 | -------------------------------------------------------------------------------- /examples/src/pages/index.vue: -------------------------------------------------------------------------------- 1 | 67 | 68 | 78 | 79 | 259 | -------------------------------------------------------------------------------- /examples/src/pages/presentation.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/src/pages/spreadsheet.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /examples/src/pages/table.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent, ref } from 'vue' 2 | import { useCopilotReadable, useCopilotAction, useCopilotContext } from '@copilotkit/vue-core' 3 | import { CopilotSidebar } from '@copilotkit/vue-ui' 4 | 5 | import { TextMessage, Role } from '@copilotkit/runtime-client-gql' 6 | 7 | export default defineComponent({ 8 | setup() { 9 | const tableData = ref([]) 10 | 11 | const { setMessages } = useCopilotContext() 12 | 13 | setMessages([ 14 | new TextMessage({ 15 | content: 16 | 'copilotkit结合el-table调用示例\n例如输入以下提示词\n1.新增一行数据\n2.删除一行数据\n3.更新一行数据\n....', 17 | role: Role.Assistant 18 | }) 19 | ]) 20 | 21 | useCopilotReadable({ 22 | description: 'The current Element-Plus table component', 23 | value: tableData.value 24 | }) 25 | 26 | useCopilotAction({ 27 | name: 'appendRow', 28 | description: 'Append row to the current table', 29 | parameters: [ 30 | { 31 | name: 'dataSource', 32 | type: 'object[]', 33 | description: 34 | 'An array of objects representing the new data source for the Element-Plus table. Each object should contain the following properties:', 35 | attributes: [ 36 | { 37 | name: 'id', 38 | type: 'number', 39 | description: 'Represents the id associated with the record in the table.' 40 | }, 41 | { 42 | name: 'date', 43 | type: 'string', 44 | description: 'Represents the date associated with the record in the table.' 45 | }, 46 | { 47 | name: 'name', 48 | type: 'string', 49 | description: 'Identifies the name associated with the record in the table.' 50 | }, 51 | { 52 | name: 'address', 53 | type: 'string', 54 | description: 'Specifies the address associated with the record in the table.' 55 | } 56 | ] 57 | } 58 | ], 59 | handler: ({ dataSource }) => { 60 | console.log('@dataSource', dataSource) 61 | tableData.value = [...tableData.value, ...dataSource] 62 | } 63 | }) 64 | 65 | useCopilotAction({ 66 | name: 'removeRow', 67 | description: 'remove row to the current table', 68 | parameters: [ 69 | { 70 | name: 'id', 71 | type: 'number', 72 | description: 'Represents the id associated with the record in the table.' 73 | } 74 | ], 75 | handler: ({ id }) => { 76 | console.log('@id', id) 77 | tableData.value = tableData.value.filter(item => item.id !== id) 78 | } 79 | }) 80 | 81 | useCopilotAction({ 82 | name: 'updateRow', 83 | description: 'update row to the current table', 84 | parameters: [ 85 | { 86 | name: 'updateData', 87 | type: 'object', 88 | description: 89 | 'An array of objects representing the new data source for the Element-Plus table. Each object should contain the following properties:', 90 | attributes: [ 91 | { 92 | name: 'id', 93 | type: 'number', 94 | description: 'Represents the id associated with the record in the table.' 95 | }, 96 | { 97 | name: 'date', 98 | type: 'string', 99 | description: 'Represents the date associated with the record in the table.' 100 | }, 101 | { 102 | name: 'name', 103 | type: 'string', 104 | description: 'Identifies the name associated with the record in the table.' 105 | }, 106 | { 107 | name: 'address', 108 | type: 'string', 109 | description: 'Specifies the address associated with the record in the table.' 110 | } 111 | ] 112 | } 113 | ], 114 | handler: ({ updateData }) => { 115 | console.log('@updateData', updateData) 116 | tableData.value = tableData.value.map(item => { 117 | if (item.id === updateData.id) { 118 | return updateData 119 | } 120 | return item 121 | }) 122 | } 123 | }) 124 | 125 | return () => { 126 | return ( 127 | <> 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | ) 136 | } 137 | } 138 | }) 139 | -------------------------------------------------------------------------------- /examples/src/pages/textarea.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 74 | 75 | 174 | -------------------------------------------------------------------------------- /examples/src/pages/todolist.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 151 | 152 | -------------------------------------------------------------------------------- /examples/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createWebHistory, createRouter } from 'vue-router' 2 | import routes from '~pages' 3 | 4 | const router = createRouter({ 5 | history: createWebHistory(), 6 | routes 7 | }) 8 | 9 | export default router 10 | -------------------------------------------------------------------------------- /examples/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | --copilot-kit-primary-color: #000; 15 | --el-color-primary: #090808 !important; 16 | --el-color-primary-light-3: rgba(0, 0, 0, 0.9) !important; 17 | --el-color-primary-light-5: rgba(0, 0, 0, 0.8) !important; 18 | --el-color-primary-light-7: rgba(0, 0, 0, 0.7) !important; 19 | --el-color-primary-light-8: rgba(0, 0, 0, 0.5) !important; 20 | --el-color-primary-light-9: rgba(0, 0, 0, 0.3) !important; 21 | --el-color-primary-dark-2: rgba(0, 0, 0, 0.9) !important; 22 | } 23 | .el-dialog { 24 | padding: 20px !important; 25 | border-radius: 10px !important; 26 | } 27 | a { 28 | font-weight: 500; 29 | color: #646cff; 30 | text-decoration: inherit; 31 | } 32 | a:hover { 33 | color: #535bf2; 34 | } 35 | 36 | body { 37 | margin: 0; 38 | display: flex; 39 | place-items: center; 40 | min-width: 320px; 41 | min-height: 100vh; 42 | } 43 | 44 | h1 { 45 | font-size: 3.2em; 46 | line-height: 1.1; 47 | } 48 | 49 | button { 50 | border-radius: 8px; 51 | border: 1px solid transparent; 52 | padding: 0.6em 1.2em; 53 | font-size: 1em; 54 | font-weight: 500; 55 | font-family: inherit; 56 | background-color: #1a1a1a; 57 | cursor: pointer; 58 | transition: border-color 0.25s; 59 | } 60 | button:hover { 61 | border-color: #646cff; 62 | } 63 | button:focus, 64 | button:focus-visible { 65 | outline: 4px auto -webkit-focus-ring-color; 66 | } 67 | 68 | .card { 69 | padding: 2em; 70 | } 71 | 72 | #app { 73 | max-width: 1280px; 74 | margin: 0 auto; 75 | padding: 2rem; 76 | text-align: center; 77 | } 78 | 79 | @media (prefers-color-scheme: light) { 80 | :root { 81 | color: #213547; 82 | background-color: #ffffff; 83 | } 84 | a:hover { 85 | color: #747bff; 86 | } 87 | button { 88 | background-color: #f9f9f9; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /examples/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// -------------------------------------------------------------------------------- /examples/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": ["./src/**/*.ts", "./src/**/*.tsx", "./src/**/*.vue"], 4 | "compilerOptions": { 5 | "sourceMap": false, 6 | "inlineSources": false, 7 | "paths": { 8 | "@copilotkit/*": ["../packages/*/src"] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import vueJsx from '@vitejs/plugin-vue-jsx' 4 | import Pages from 'vite-plugin-pages' 5 | import { nodePolyfills } from 'vite-plugin-node-polyfills' 6 | 7 | import { resolve } from 'path' 8 | import fs from 'fs-extra' 9 | import { glob } from 'glob' 10 | import UnoCSS from 'unocss/vite' 11 | 12 | function getWorkspaceAlias() { 13 | const basePath = resolve(__dirname, '../') 14 | const pkg = fs.readJSONSync(resolve(basePath, 'package.json')) || {} 15 | const alias: Record = {} 16 | const workspaces = pkg.workspaces 17 | if (Array.isArray(workspaces)) { 18 | workspaces.forEach(pattern => { 19 | const found = glob.sync(pattern, { cwd: basePath }) 20 | found.forEach(name => { 21 | try { 22 | const pkg = fs.readJSONSync(resolve(basePath, name, './package.json')) 23 | alias[pkg.name] = resolve(basePath, name, './src') 24 | } catch (error) { 25 | /* empty */ 26 | } 27 | }) 28 | }) 29 | } 30 | return alias 31 | } 32 | 33 | // https://vitejs.dev/config/ 34 | export default defineConfig({ 35 | plugins: [ 36 | vue(), 37 | vueJsx(), 38 | Pages({ 39 | extensions: ['vue', 'tsx'] 40 | }), 41 | nodePolyfills(), 42 | UnoCSS() 43 | ], 44 | resolve: { 45 | alias: { 46 | ...getWorkspaceAlias() 47 | } 48 | }, 49 | build: { 50 | minify: false 51 | } 52 | }) 53 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.2", 3 | "npmClient": "pnpm", 4 | "command": { 5 | "version": { 6 | "forcePublish": true, 7 | "exact": true, 8 | "message": "chore(release): 😊 publish %s" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-copilotkit", 3 | "private": false, 4 | "workspaces": [ 5 | "examples", 6 | "packages/*" 7 | ], 8 | "scripts": { 9 | "dev": "pnpm run -F examples dev", 10 | "build": "turbo build", 11 | "clean": "lerna clean" 12 | }, 13 | "dependencies": { 14 | "vue": "^3.4.31" 15 | }, 16 | "devDependencies": { 17 | "@types/node": "^18.11.17", 18 | "@copilotkit/runtime": "^1.1.1", 19 | "openai": "^4.55.5", 20 | "fs-extra": "^11.2.0", 21 | "glob": "^11.0.0", 22 | "lerna": "^8.1.8", 23 | "prettier": "^3.2.5", 24 | "turbo": "^2.0.6", 25 | "typescript": "^5.2.3" 26 | }, 27 | "packageManager": "pnpm@9.5.0" 28 | } 29 | -------------------------------------------------------------------------------- /packages/vite-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@copilotkit/vite-config", 3 | "private": false, 4 | "version": "1.0.3", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "build": "tsup --clean" 10 | }, 11 | "devDependencies": { 12 | "tsup": "^8.2.4" 13 | }, 14 | "dependencies": { 15 | "@vitejs/plugin-vue": "^5.0.5", 16 | "@vitejs/plugin-vue-jsx": "^4.0.0", 17 | "vite": "^5.3.4", 18 | "vite-plugin-dts": "^4.0.1", 19 | "vite-plugin-node-polyfills": "^0.22.0" 20 | }, 21 | "publishConfig": { 22 | "access": "public" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/vite-config/src/index.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig as defineViteConfig, mergeConfig, UserConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import vueJsx from '@vitejs/plugin-vue-jsx' 4 | import dts from 'vite-plugin-dts' 5 | import { nodePolyfills } from 'vite-plugin-node-polyfills' 6 | 7 | export function defineConfig(config: UserConfig) { 8 | const baseConfig: UserConfig = { 9 | plugins: [vue(), vueJsx(), dts({ rollupTypes: true }), nodePolyfills()], 10 | build: { 11 | lib: { 12 | entry: 'src/index.ts', 13 | formats: ['es', 'cjs'], 14 | // 输出文件名 15 | fileName: 'index' 16 | }, 17 | minify: false, 18 | cssMinify: false, 19 | rollupOptions: { 20 | // 确保外部化那些你不想打包进库的依赖 21 | external: ['vue'] 22 | } 23 | } 24 | } 25 | return defineViteConfig(mergeConfig(baseConfig, config)) 26 | } 27 | -------------------------------------------------------------------------------- /packages/vite-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src/**/*.ts", "./src/**/*.tsx", "./src/**/*.vue"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/vite-config/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup' 2 | 3 | export default defineConfig({ 4 | entry: ['src/index.ts'], 5 | format: ['esm', 'cjs'], 6 | dts: true, 7 | minify: false 8 | }) 9 | -------------------------------------------------------------------------------- /packages/vue-core/.autocodercommands/hello.md: -------------------------------------------------------------------------------- 1 | 和我说hello {{name}} -------------------------------------------------------------------------------- /packages/vue-core/.autocoderignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /packages/vue-core/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .auto-coder/ 3 | /actions/ 4 | /output.txt -------------------------------------------------------------------------------- /packages/vue-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@copilotkit/vue-core", 3 | "private": false, 4 | "version": "1.0.3", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.mjs", 7 | "exports": { 8 | ".": { 9 | "import": "./dist/index.mjs", 10 | "require": "./dist/index.js", 11 | "types": "./dist/index.d.ts" 12 | } 13 | }, 14 | "types": "./dist/index.d.ts", 15 | "scripts": { 16 | "build": "vite build" 17 | }, 18 | "devDependencies": { 19 | "@copilotkit/vite-config": "workspace:*", 20 | "vite": "^5.3.4" 21 | }, 22 | "dependencies": { 23 | "@copilotkit/runtime-client-gql": "^1.1.0", 24 | "@copilotkit/shared": "^1.1.0" 25 | }, 26 | "publishConfig": { 27 | "access": "public" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/vue-core/src/components/copilotkit-props.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Props for CopilotKit. 3 | */ 4 | 5 | export interface CopilotKitProps { 6 | /** 7 | * Your Copilot Cloud API key. 8 | */ 9 | publicApiKey?: string 10 | 11 | /** 12 | * Cloud feature: Restrict input to a specific topic. 13 | */ 14 | cloudRestrictToTopic?: { 15 | validTopics?: string[] 16 | invalidTopics?: string[] 17 | } 18 | 19 | /** 20 | * the endpoint for the Copilot Runtime instance. 21 | */ 22 | runtimeUrl?: string 23 | 24 | /** 25 | * The endpoint for the Copilot transcribe audio service. 26 | */ 27 | transcribeAudioUrl?: string 28 | 29 | /** 30 | * The endpoint for the Copilot text to speech service. 31 | */ 32 | textToSpeechUrl?: string 33 | 34 | /** 35 | * Additional headers to be sent with the request. 36 | * 37 | * For example: 38 | * ```js 39 | * { 40 | * 'Authorization': 'Bearer your_token_here' 41 | * } 42 | * ``` 43 | */ 44 | headers?: Record 45 | 46 | /** 47 | * Additional body params to be sent with the request 48 | * For example: 49 | * ```js 50 | * { 51 | * 'message': 'Hello, world!' 52 | * } 53 | * ``` 54 | */ 55 | body?: Record 56 | 57 | /** 58 | * Custom properties to be sent with the request 59 | * For example: 60 | * ```js 61 | * { 62 | * 'user_id': 'users_id', 63 | * } 64 | * ``` 65 | */ 66 | properties?: Record 67 | 68 | /** 69 | * Indicates whether the user agent should send or receive cookies from the other domain 70 | * in the case of cross-origin requests. 71 | */ 72 | credentials?: any 73 | 74 | /** 75 | * Whether to show the dev console. 76 | * 77 | * If set to "auto", the dev console will be show on localhost only. 78 | */ 79 | showDevConsole?: boolean | 'auto' 80 | } 81 | -------------------------------------------------------------------------------- /packages/vue-core/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export type { CopilotKitProps } from './copilotkit-props' 2 | export { CopilotKit, defaultCopilotContextCategories } from './copilotkit' 3 | -------------------------------------------------------------------------------- /packages/vue-core/src/context/copilot-context.ts: -------------------------------------------------------------------------------- 1 | import { inject, Ref } from 'vue' 2 | import { CopilotCloudConfig, FunctionCallHandler } from '@copilotkit/shared' 3 | import { Message } from '@copilotkit/runtime-client-gql' 4 | 5 | import { ActionRenderProps, FrontendAction } from '../types/frontend-action' 6 | import { DocumentPointer } from '../types' 7 | import { CopilotChatSuggestionConfiguration } from '../types/chat-suggestion-configuration' 8 | 9 | type TreeNodeId = string 10 | 11 | /** 12 | * Interface for the configuration of the Copilot API. 13 | */ 14 | export interface CopilotApiConfig { 15 | /** 16 | * The public API key for Copilot Cloud. 17 | */ 18 | publicApiKey?: string 19 | 20 | /** 21 | * The configuration for Copilot Cloud. 22 | */ 23 | cloud?: CopilotCloudConfig 24 | 25 | /** 26 | * The endpoint for the chat API. 27 | */ 28 | chatApiEndpoint: string 29 | 30 | /** 31 | * The endpoint for the Copilot transcribe audio service. 32 | */ 33 | transcribeAudioUrl?: string 34 | 35 | /** 36 | * The endpoint for the Copilot text to speech service. 37 | */ 38 | textToSpeechUrl?: string 39 | 40 | /** 41 | * additional headers to be sent with the request 42 | * @default {} 43 | * @example 44 | * ``` 45 | * { 46 | * 'Authorization': 'Bearer your_token_here' 47 | * } 48 | * ``` 49 | */ 50 | headers: Record 51 | 52 | /** 53 | * Custom properties to be sent with the request 54 | * @default {} 55 | * @example 56 | * ``` 57 | * { 58 | * 'user_id': 'user_id' 59 | * } 60 | * ``` 61 | */ 62 | properties?: Record 63 | 64 | /** 65 | * Indicates whether the user agent should send or receive cookies from the other domain 66 | * in the case of cross-origin requests. 67 | */ 68 | credentials?: RequestCredentials 69 | } 70 | 71 | export type InChatRenderFunction = (props: ActionRenderProps) => any 72 | 73 | export interface CopilotContextParams { 74 | chatComponentsCache: Ref> 75 | // function-calling 76 | actions: Ref>> 77 | setAction: (id: string, action: FrontendAction) => void 78 | removeAction: (id: string) => void 79 | 80 | getFunctionCallHandler: (customEntryPoints?: Record>) => FunctionCallHandler 81 | 82 | // text context 83 | addContext: (context: string, parentId?: string, categories?: string[]) => TreeNodeId 84 | removeContext: (id: TreeNodeId) => void 85 | getContextString: (documents: DocumentPointer[], categories: string[]) => string 86 | 87 | // document context 88 | addDocumentContext: (documentPointer: DocumentPointer, categories?: string[]) => TreeNodeId 89 | removeDocumentContext: (documentId: string) => void 90 | getDocumentsContext: (categories: string[]) => DocumentPointer[] 91 | 92 | // chat 93 | messages: Ref 94 | setMessages: any 95 | 96 | isLoading: Ref 97 | setIsLoading: any 98 | 99 | chatSuggestionConfiguration: Ref<{ [key: string]: CopilotChatSuggestionConfiguration }> 100 | addChatSuggestionConfiguration: (id: string, suggestion: CopilotChatSuggestionConfiguration) => void 101 | removeChatSuggestionConfiguration: (id: string) => void 102 | 103 | chatInstructions: Ref 104 | setChatInstructions: any 105 | 106 | // api endpoints 107 | copilotApiConfig: CopilotApiConfig 108 | 109 | showDevConsole: boolean | 'auto' 110 | } 111 | 112 | export const CopilotKitContext = Symbol() 113 | 114 | export function useCopilotContext() { 115 | const ctx = inject(CopilotKitContext) 116 | 117 | if (!ctx) { 118 | throw new Error('Remember to wrap your app in a ` {...} ` !!!') 119 | } 120 | 121 | return ctx 122 | } 123 | -------------------------------------------------------------------------------- /packages/vue-core/src/context/index.ts: -------------------------------------------------------------------------------- 1 | export { CopilotKitContext, useCopilotContext } from './copilot-context' 2 | export type { CopilotContextParams, CopilotApiConfig, InChatRenderFunction } from './copilot-context' 3 | -------------------------------------------------------------------------------- /packages/vue-core/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useCopilotChat } from './use-copilot-chat' 2 | export { useCopilotReadable } from './use-copilot-readable' 3 | export { useCopilotAction } from './use-copilot-action' 4 | export { useMakeCopilotDocumentReadable } from './use-make-copilot-document-readable' 5 | -------------------------------------------------------------------------------- /packages/vue-core/src/hooks/use-copilot-action.ts: -------------------------------------------------------------------------------- 1 | import { ref, onMounted, onUnmounted } from 'vue' 2 | import { Parameter, randomId } from '@copilotkit/shared' 3 | 4 | import { useCopilotContext } from '../context' 5 | import { FrontendAction } from '../types/frontend-action' 6 | 7 | export function useCopilotAction(action: FrontendAction) { 8 | const { setAction, removeAction, actions, chatComponentsCache } = useCopilotContext() 9 | const idRef = ref(randomId()) 10 | 11 | if (actions.value[idRef.value]) { 12 | actions.value[idRef.value].handler = action.handler as any 13 | if (typeof action.render === 'function') { 14 | if (chatComponentsCache.value !== null) { 15 | chatComponentsCache.value[action.name] = action.render 16 | } 17 | } 18 | } 19 | 20 | setAction(idRef.value, action as any) 21 | 22 | onUnmounted(() => { 23 | removeAction(idRef.value) 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /packages/vue-core/src/hooks/use-copilot-chat.ts: -------------------------------------------------------------------------------- 1 | import { Message, Role, TextMessage } from '@copilotkit/runtime-client-gql' 2 | 3 | import { useCopilotContext } from '../context/copilot-context' 4 | 5 | import { SystemMessageFunction } from '../types' 6 | 7 | import { useChat } from './use-chat' 8 | 9 | import { defaultCopilotContextCategories } from '../components' 10 | 11 | export interface UseCopilotChatOptions { 12 | /** 13 | * A unique identifier for the chat. If not provided, a random one will be 14 | * generated. When provided, the `useChat` hook with the same `id` will 15 | * have shared states across components. 16 | */ 17 | id?: string 18 | 19 | /** 20 | * HTTP headers to be sent with the API request. 21 | */ 22 | headers?: Record | Headers 23 | 24 | /** 25 | * Extra body object to be sent with the API request. 26 | * @example 27 | * Send a `sessionId` to the API along with the messages. 28 | * ```js 29 | * useChat({ 30 | * body: { 31 | * sessionId: '123', 32 | * } 33 | * }) 34 | * ``` 35 | */ 36 | body?: object 37 | /** 38 | * System messages of the chat. Defaults to an empty array. 39 | */ 40 | initialMessages?: Message[] 41 | 42 | /** 43 | * A function to generate the system message. Defaults to `defaultSystemMessage`. 44 | */ 45 | makeSystemMessage?: SystemMessageFunction 46 | } 47 | 48 | export function useCopilotChat({ makeSystemMessage, ...options }: UseCopilotChatOptions = {}) { 49 | const { 50 | getContextString, 51 | getFunctionCallHandler, 52 | copilotApiConfig, 53 | messages, 54 | setMessages, 55 | isLoading, 56 | setIsLoading, 57 | chatInstructions, 58 | actions 59 | } = useCopilotContext() 60 | 61 | const deleteMessage = (messageId: string) => { 62 | setMessages(messages.value.filter(message => message.id !== messageId)) 63 | } 64 | 65 | const makeSystemMessageCallback = () => { 66 | const systemMessageMaker = makeSystemMessage || defaultSystemMessage 67 | // this always gets the latest context string 68 | const contextString = getContextString([], defaultCopilotContextCategories) // TODO: make the context categories configurable 69 | 70 | return new TextMessage({ 71 | content: systemMessageMaker(contextString, chatInstructions.value), 72 | role: Role.System 73 | }) 74 | } 75 | 76 | const { append, reload, stop } = useChat({ 77 | ...options, 78 | // @ts-ignore 79 | actions: Object.values(actions.value), 80 | copilotConfig: copilotApiConfig, 81 | initialMessages: options.initialMessages || [], 82 | onFunctionCall: getFunctionCallHandler(), 83 | messages, 84 | setMessages, 85 | // @ts-ignore 86 | makeSystemMessageCallback, 87 | isLoading, 88 | setIsLoading 89 | }) 90 | 91 | return { 92 | visibleMessages: messages, 93 | appendMessage: append, 94 | setMessages, 95 | reloadMessages: reload, 96 | stopGeneration: stop, 97 | deleteMessage, 98 | isLoading 99 | } 100 | } 101 | 102 | export function defaultSystemMessage(contextString: string, additionalInstructions?: string): string { 103 | return ( 104 | ` 105 | Please act as an efficient, competent, conscientious, and industrious professional assistant. 106 | 107 | Help the user achieve their goals, and you do so in a way that is as efficient as possible, without unnecessary fluff, but also without sacrificing professionalism. 108 | Always be polite and respectful, and prefer brevity over verbosity. 109 | 110 | The user has provided you with the following context: 111 | \`\`\` 112 | ${contextString} 113 | \`\`\` 114 | 115 | They have also provided you with functions you can call to initiate actions on their behalf, or functions you can call to receive more information. 116 | 117 | Please assist them as best you can. 118 | 119 | You can ask them for clarifying questions if needed, but don't be annoying about it. If you can reasonably 'fill in the blanks' yourself, do so. 120 | 121 | If you would like to call a function, call it without saying anything else. 122 | ` + (additionalInstructions ? `\n\n${additionalInstructions}` : '') 123 | ) 124 | } 125 | -------------------------------------------------------------------------------- /packages/vue-core/src/hooks/use-copilot-readable.ts: -------------------------------------------------------------------------------- 1 | import { ref, onMounted, onUnmounted, watchEffect, watch } from 'vue' 2 | import { useCopilotContext } from '../context' 3 | 4 | /** 5 | * Options for the useCopilotReadable hook. 6 | */ 7 | export interface UseCopilotReadableOptions { 8 | /** 9 | * The description of the information to be added to the Copilot context. 10 | */ 11 | description: string 12 | /** 13 | * The value to be added to the Copilot context. 14 | */ 15 | value: any 16 | /** 17 | * The ID of the parent context, if any. 18 | */ 19 | parentId?: string 20 | /** 21 | * An array of categories to control which context are visible where. Particularly useful 22 | * with CopilotTextarea (see `useMakeAutosuggestionFunction`) 23 | */ 24 | categories?: string[] 25 | 26 | /** 27 | * A custom conversion function to use to serialize the value to a string. If not provided, the value 28 | * will be serialized using `JSON.stringify`. 29 | */ 30 | convert?: (description: string, value: any) => string 31 | } 32 | 33 | /** 34 | * Adds the given information to the Copilot context to make it readable by Copilot. 35 | */ 36 | export function useCopilotReadable({ description, value, parentId, categories, convert }: UseCopilotReadableOptions) { 37 | const { addContext, removeContext } = useCopilotContext() 38 | 39 | const idRef = ref() 40 | 41 | convert = convert || convertToJSON 42 | 43 | const information = convert(description, value) 44 | 45 | // watchEffect(() => { 46 | // const id = addContext(information, parentId, categories) 47 | // idRef.value = id 48 | // if (idRef.value) { 49 | // // removeContext(idRef.value) 50 | // } 51 | // }) 52 | watch(() => [description, value,parentId,categories], () => { 53 | const information = convert(description, value) 54 | const id = addContext(information, parentId, categories) 55 | idRef.value = id 56 | },{ 57 | deep: true, 58 | immediate: true 59 | }) 60 | } 61 | 62 | function convertToJSON(description: string, value: any): string { 63 | return `${description}: ${typeof value === 'string' ? value : JSON.stringify(value)}` 64 | } 65 | -------------------------------------------------------------------------------- /packages/vue-core/src/hooks/use-flat-category-store.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue' 2 | 3 | export type FlatCategoryStoreId = string 4 | 5 | interface FlatCategoryStoreElement { 6 | id: FlatCategoryStoreId 7 | value: T 8 | categories: Set 9 | } 10 | 11 | export default function useFlatCategoryStore() { 12 | const elements = ref(new Map>()) 13 | 14 | const addElement = (value: T, categories: string[]) => {} 15 | 16 | const removeElement = (id: FlatCategoryStoreId) => {} 17 | 18 | const allElements = (categories: string[]) => {} 19 | 20 | return { addElement, removeElement, allElements } 21 | } 22 | -------------------------------------------------------------------------------- /packages/vue-core/src/hooks/use-make-copilot-document-readable.ts: -------------------------------------------------------------------------------- 1 | import { onMounted, onBeforeUnmount, ref, watchEffect } from 'vue' 2 | import { useCopilotContext } from '../context/copilot-context' 3 | import { DocumentPointer } from '../types' 4 | 5 | /** 6 | * Makes a document readable by Copilot. 7 | * @param document The document to make readable. 8 | * @param categories The categories to associate with the document. 9 | * @param dependencies The dependencies to use for the effect. 10 | * @returns The id of the document. 11 | */ 12 | export function useMakeCopilotDocumentReadable( 13 | document: DocumentPointer, 14 | categories: string[] = [], 15 | dependencies: any[] = [] 16 | ): string | undefined { 17 | const { addDocumentContext, removeDocumentContext } = useCopilotContext() 18 | const idRef = ref(undefined) 19 | 20 | const addDocument = () => { 21 | const id = addDocumentContext(document, categories) 22 | idRef.value = id 23 | } 24 | 25 | onMounted(() => { 26 | addDocument() 27 | }) 28 | 29 | onBeforeUnmount(() => { 30 | if (idRef.value) { 31 | removeDocumentContext(idRef.value) 32 | } 33 | }) 34 | 35 | watchEffect(() => { 36 | // Re-run the effect when dependencies change 37 | addDocument() 38 | return () => { 39 | if (idRef.value) { 40 | removeDocumentContext(idRef.value) 41 | } 42 | } 43 | }) 44 | 45 | return idRef.value 46 | } 47 | -------------------------------------------------------------------------------- /packages/vue-core/src/hooks/use-tree.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue' 2 | import { randomId } from '@copilotkit/shared' 3 | 4 | export type TreeNodeId = string 5 | 6 | export interface TreeNode { 7 | id: TreeNodeId 8 | value: string 9 | children: TreeNode[] 10 | parentId?: TreeNodeId 11 | categories: Set 12 | } 13 | 14 | export type Tree = TreeNode[] 15 | 16 | const findNode = (nodes: Tree, id: TreeNodeId): TreeNode | undefined => { 17 | for (const node of nodes) { 18 | if (node.id === id) { 19 | return node 20 | } 21 | const result = findNode(node.children, id) 22 | if (result) { 23 | return result 24 | } 25 | } 26 | return undefined 27 | } 28 | 29 | const removeNode = (nodes: Tree, id: TreeNodeId): Tree => { 30 | return nodes.reduce((result: Tree, node) => { 31 | if (node.id !== id) { 32 | const newNode = { ...node, children: removeNode(node.children, id) } 33 | result.push(newNode) 34 | } 35 | return result 36 | }, []) 37 | } 38 | 39 | const addNode = (nodes: Tree, newNode: TreeNode, parentId?: TreeNodeId): Tree => { 40 | if (!parentId) { 41 | return [...nodes, newNode] 42 | } 43 | return nodes.map(node => { 44 | if (node.id === parentId) { 45 | return { ...node, children: [...node.children, newNode] } 46 | } else if (node.children.length) { 47 | return { ...node, children: addNode(node.children, newNode, parentId) } 48 | } 49 | return node 50 | }) 51 | } 52 | 53 | const treeIndentationRepresentation = (index: number, indentLevel: number): string => { 54 | if (indentLevel === 0) { 55 | return (index + 1).toString() 56 | } else if (indentLevel === 1) { 57 | return String.fromCharCode(65 + index) // 65 is the ASCII value for 'A' 58 | } else if (indentLevel === 2) { 59 | return String.fromCharCode(97 + index) // 97 is the ASCII value for 'a' 60 | } else { 61 | return '-' 62 | } 63 | } 64 | 65 | const printNode = (node: TreeNode, prefix = '', indentLevel = 0): string => { 66 | const indent = ' '.repeat(3).repeat(indentLevel) 67 | 68 | const prefixPlusIndentLength = prefix.length + indent.length 69 | const subsequentLinesPrefix = ' '.repeat(prefixPlusIndentLength) 70 | 71 | const valueLines = node.value.split('\n') 72 | 73 | const outputFirstLine = `${indent}${prefix}${valueLines[0]}` 74 | const outputSubsequentLines = valueLines 75 | .slice(1) 76 | .map(line => `${subsequentLinesPrefix}${line}`) 77 | .join('\n') 78 | 79 | let output = `${outputFirstLine}\n` 80 | if (outputSubsequentLines) { 81 | output += `${outputSubsequentLines}\n` 82 | } 83 | 84 | const childPrePrefix = ' '.repeat(prefix.length) 85 | 86 | node.children.forEach( 87 | (child, index) => 88 | (output += printNode( 89 | child, 90 | `${childPrePrefix}${treeIndentationRepresentation(index, indentLevel + 1)}. `, 91 | indentLevel + 1 92 | )) 93 | ) 94 | return output 95 | } 96 | 97 | export default function useTree() { 98 | const tree = ref([]) 99 | 100 | const addElement = (value: string, categories: string[], parentId?: string) => { 101 | const newNodeId = randomId() // Generate new ID outside of dispatch 102 | const newNode: TreeNode = { 103 | id: newNodeId, 104 | value, 105 | children: [], 106 | categories: new Set(categories) 107 | } 108 | tree.value = addNode(tree.value, newNode, parentId) 109 | return newNodeId 110 | } 111 | 112 | const removeElement = (id: TreeNodeId) => { 113 | tree.value = removeNode(tree.value, id) 114 | } 115 | 116 | const printTree = (categories: string[]) => { 117 | const categoriesSet = new Set(categories) 118 | 119 | let output = '' 120 | tree.value.forEach((node, index) => { 121 | // if the node does not have any of the desired categories, continue to the next node 122 | if (!setsHaveIntersection(categoriesSet, node.categories)) { 123 | return 124 | } 125 | 126 | // add a new line before each node except the first one 127 | if (index !== 0) { 128 | output += '\n' 129 | } 130 | 131 | output += printNode(node, `${treeIndentationRepresentation(index, 0)}. `) 132 | }) 133 | return output 134 | } 135 | 136 | return { tree, addElement, removeElement, printTree } 137 | } 138 | 139 | function setsHaveIntersection(setA: Set, setB: Set): boolean { 140 | const [smallerSet, largerSet] = setA.size <= setB.size ? [setA, setB] : [setB, setA] 141 | 142 | for (let item of smallerSet) { 143 | if (largerSet.has(item)) { 144 | return true 145 | } 146 | } 147 | 148 | return false 149 | } 150 | -------------------------------------------------------------------------------- /packages/vue-core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components' 2 | export * from './types' 3 | export * from './context' 4 | export * from './hooks' 5 | -------------------------------------------------------------------------------- /packages/vue-core/src/types/chat-suggestion-configuration.ts: -------------------------------------------------------------------------------- 1 | export interface CopilotChatSuggestionConfiguration { 2 | /** 3 | * A prompt or instructions for the GPT to generate suggestions. 4 | */ 5 | instructions: string 6 | 7 | /** 8 | * The minimum number of suggestions to generate. Defaults to `1`. 9 | * @default 1 10 | */ 11 | minSuggestions?: number 12 | 13 | /** 14 | * The maximum number of suggestions to generate. Defaults to `3`. 15 | * @default 1 16 | */ 17 | maxSuggestions?: number 18 | 19 | /** 20 | * An optional class name to apply to the suggestions. 21 | */ 22 | className?: string 23 | } 24 | -------------------------------------------------------------------------------- /packages/vue-core/src/types/document-pointer.ts: -------------------------------------------------------------------------------- 1 | export interface DocumentPointer { 2 | id: string 3 | name: string 4 | sourceApplication: string 5 | iconImageUri: string 6 | getContents: () => string 7 | } 8 | -------------------------------------------------------------------------------- /packages/vue-core/src/types/frontend-action.ts: -------------------------------------------------------------------------------- 1 | import { Action, Parameter, MappedParameterTypes } from '@copilotkit/shared' 2 | 3 | interface InProgressState { 4 | status: 'inProgress' 5 | args: Partial> 6 | result: undefined 7 | } 8 | 9 | interface ExecutingState { 10 | status: 'executing' 11 | args: MappedParameterTypes 12 | result: undefined 13 | } 14 | 15 | interface CompleteState { 16 | status: 'complete' 17 | args: MappedParameterTypes 18 | result: any 19 | } 20 | 21 | interface InProgressStateNoArgs { 22 | status: 'inProgress' 23 | args: Partial> 24 | result: undefined 25 | } 26 | 27 | interface ExecutingStateNoArgs { 28 | status: 'executing' 29 | args: MappedParameterTypes 30 | result: undefined 31 | } 32 | 33 | interface CompleteStateNoArgs { 34 | status: 'complete' 35 | args: MappedParameterTypes 36 | result: any 37 | } 38 | 39 | export type ActionRenderProps = 40 | | CompleteState 41 | | ExecutingState 42 | | InProgressState 43 | 44 | export type ActionRenderPropsNoArgs = 45 | | CompleteStateNoArgs 46 | | ExecutingStateNoArgs 47 | | InProgressStateNoArgs 48 | 49 | export type FrontendAction = Action & { 50 | render?: any 51 | } 52 | 53 | export type RenderFunctionStatus = ActionRenderProps['status'] 54 | -------------------------------------------------------------------------------- /packages/vue-core/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type { DocumentPointer } from './document-pointer' 2 | export type { SystemMessageFunction } from './system-message' 3 | export type { ActionRenderProps, RenderFunctionStatus } from './frontend-action' 4 | export type { CopilotChatSuggestionConfiguration } from './chat-suggestion-configuration' 5 | -------------------------------------------------------------------------------- /packages/vue-core/src/types/system-message.ts: -------------------------------------------------------------------------------- 1 | export type SystemMessageFunction = (contextString: string, additionalInstructions?: string) => string 2 | -------------------------------------------------------------------------------- /packages/vue-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./src/**/*.ts", "./src/**/*.tsx", "./src/**/*.vue"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/vue-core/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@copilotkit/vite-config' 2 | 3 | // https://vitejs.dev/config/ 4 | export default defineConfig({ 5 | build: { 6 | rollupOptions: { 7 | external: ['vue','@copilotkit/runtime-client-gql','@copilotkit/shared'] 8 | } 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /packages/vue-textarea/README.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 |
4 | 5 | `` 是一个 Vue 组件,可作为标准 `