;
isSubTask: boolean;
modelOverride?: DisplayModel;
+ taskId: string;
}) {
const { toolset, instructions } = useMcp();
const mcpInfo = useLatest({ toolset, instructions });
@@ -42,6 +44,7 @@ export function useLiveChatKitGetters({
const environment = await vscodeHost.readEnvironment({
isSubTask,
webviewKind: globalThis.POCHI_WEBVIEW_KIND,
+ taskId,
});
let userEdits: FileDiff[] | undefined;
@@ -60,7 +63,7 @@ export function useLiveChatKitGetters({
userEdits,
} satisfies Environment;
},
- [todos, isSubTask],
+ [todos, isSubTask, taskId],
);
return {
diff --git a/packages/vscode-webui/src/features/chat/page.tsx b/packages/vscode-webui/src/features/chat/page.tsx
index 06de405b1..3cf5802ea 100644
--- a/packages/vscode-webui/src/features/chat/page.tsx
+++ b/packages/vscode-webui/src/features/chat/page.tsx
@@ -107,6 +107,7 @@ function Chat({ user, uid, info }: ChatProps) {
const getters = useLiveChatKitGetters({
todos: todosRef,
isSubTask,
+ taskId: uid,
});
useRestoreTaskModel(task, isModelsLoading, updateSelectedModelId);
diff --git a/packages/vscode-webui/src/features/settings/components/sections/custom-agent-section.tsx b/packages/vscode-webui/src/features/settings/components/sections/custom-agent-section.tsx
index 30097ba20..f475f4ae6 100644
--- a/packages/vscode-webui/src/features/settings/components/sections/custom-agent-section.tsx
+++ b/packages/vscode-webui/src/features/settings/components/sections/custom-agent-section.tsx
@@ -9,7 +9,7 @@ import type {
CustomAgentFile,
InvalidCustomAgentFile,
} from "@getpochi/common/vscode-webui-bridge";
-import { isValidCustomAgentFile } from "@getpochi/common/vscode-webui-bridge";
+import { isValidCustomAgent } from "@getpochi/common/vscode-webui-bridge";
import { AlertTriangle, Bot, Edit } from "lucide-react";
import { useTranslation } from "react-i18next";
import { AccordionSection } from "../ui/accordion-section";
@@ -56,7 +56,7 @@ export const CustomAgentSection: React.FC = () => {
return (
{customAgents.map((agent) => {
- const isValid = isValidCustomAgentFile(agent);
+ const isValid = isValidCustomAgent(agent);
const subtitle = !isValid ? (
diff --git a/packages/vscode-webui/src/i18n/locales/en.json b/packages/vscode-webui/src/i18n/locales/en.json
index 10c2897d7..79ef9b03c 100644
--- a/packages/vscode-webui/src/i18n/locales/en.json
+++ b/packages/vscode-webui/src/i18n/locales/en.json
@@ -27,6 +27,14 @@
},
"chat": {
"attachmentTooltip": "Attach files to chat. You can also drag and drop files or paste them into the chat input box.",
+ "createPlanTooltip": "Create a plan for the task",
+ "planCard": {
+ "title": "Implementation Plan",
+ "status": "Ready for review",
+ "reviewButton": "Review & Comment",
+ "executeButton": "Execute Plan",
+ "executePrompt": "Please implement the plan specified in {{path}}."
+ },
"queuedMessages": "Queued Messages ({{count}})",
"copyImage": "Copy Image",
"openImage": "Open Image",
diff --git a/packages/vscode-webui/src/i18n/locales/jp.json b/packages/vscode-webui/src/i18n/locales/jp.json
index 40fdd2519..c29d2e47d 100644
--- a/packages/vscode-webui/src/i18n/locales/jp.json
+++ b/packages/vscode-webui/src/i18n/locales/jp.json
@@ -26,7 +26,15 @@
"required": "Pochi を使用するには、フォルダーまたはワークスペースを開いてください。"
},
"chat": {
- "attachmentTooltip": "ファイルをチャットに添付します。ファイルをドラッグ&ドロップするか、チャット入力欄に貼り付けることもできます。",
+ "attachmentTooltip": "ファイルをチャットに添付します。ファイ ルをドラッグ&ドロップするか、チャット入力欄に貼り付けることもできます。",
+ "createPlanTooltip": "タスクの計画を作成",
+ "planCard": {
+ "title": "実装計画",
+ "status": "レビュー待ち",
+ "reviewButton": "レビュー&コメント",
+ "executeButton": "計画を実行",
+ "executePrompt": "{{path}} に指定された計画を実装してください。"
+ },
"queuedMessages": "キュー内のメッセージ ({{count}})",
"copyImage": "画像をコピー",
"openImage": "画像を開く",
diff --git a/packages/vscode-webui/src/i18n/locales/ko.json b/packages/vscode-webui/src/i18n/locales/ko.json
index f493abbdd..85b020c05 100644
--- a/packages/vscode-webui/src/i18n/locales/ko.json
+++ b/packages/vscode-webui/src/i18n/locales/ko.json
@@ -27,6 +27,14 @@
},
"chat": {
"attachmentTooltip": "채팅에 파일을 첨부합니다. 파일을 드래그 앤 드롭하거나 채팅 입력란에 붙여넣을 수도 있습니다.",
+ "createPlanTooltip": "작업 계획 생성",
+ "planCard": {
+ "title": "구현 계획",
+ "status": "검토 준비 완료",
+ "reviewButton": "검토 및 댓글",
+ "executeButton": "계획 실행",
+ "executePrompt": "{{path}}에 명시된 계획을 구현해 주세요."
+ },
"queuedMessages": "대기 중인 메시지 ({{count}})",
"copyImage": "이미지 복사",
"openImage": "이미지 열기",
diff --git a/packages/vscode-webui/src/i18n/locales/zh.json b/packages/vscode-webui/src/i18n/locales/zh.json
index cbbcf4053..34c239472 100644
--- a/packages/vscode-webui/src/i18n/locales/zh.json
+++ b/packages/vscode-webui/src/i18n/locales/zh.json
@@ -26,7 +26,15 @@
"required": "要使用 Pochi,请打开一个文件夹或工作区。"
},
"chat": {
- "attachmentTooltip": "附加文件到对话。您也可以拖放文件或将其粘贴到聊天输入框中。",
+ "attachmentTooltip": "附加文件到对话。您也可以拖放文件或将其 粘贴到聊天输入框中。",
+ "createPlanTooltip": "为任务创建计划",
+ "planCard": {
+ "title": "实施计划",
+ "status": "待审查",
+ "reviewButton": "审查与评论",
+ "executeButton": "执行计划",
+ "executePrompt": "请实施 {{path}} 中指定的计划。"
+ },
"queuedMessages": "排队中的消息 ({{count}})",
"copyImage": "复制图片",
"openImage": "打开图片",
diff --git a/packages/vscode-webui/src/lib/constants.ts b/packages/vscode-webui/src/lib/constants.ts
index 49f16fe53..3b17143d4 100644
--- a/packages/vscode-webui/src/lib/constants.ts
+++ b/packages/vscode-webui/src/lib/constants.ts
@@ -1,4 +1,10 @@
-export const CustomHtmlTags = ["file", "workflow", "custom-agent", "issue"];
+export const CustomHtmlTags = [
+ "file",
+ "workflow",
+ "custom-agent",
+ "issue",
+ "plan-card",
+];
export const MaxAttachments = 4;
export const MaxFileSize = 20 * 1024 * 1024; // 20MB
diff --git a/packages/vscode-webui/src/lib/hooks/use-custom-agents.ts b/packages/vscode-webui/src/lib/hooks/use-custom-agents.ts
index 97ea1a72f..d6c3015c8 100644
--- a/packages/vscode-webui/src/lib/hooks/use-custom-agents.ts
+++ b/packages/vscode-webui/src/lib/hooks/use-custom-agents.ts
@@ -2,7 +2,7 @@ import { useSelectedModels } from "@/features/settings";
import {
type CustomAgentFile,
type ValidCustomAgentFile,
- isValidCustomAgentFile,
+ isValidCustomAgent,
} from "@getpochi/common/vscode-webui-bridge";
import { threadSignal } from "@quilted/threads/signals";
import { useQuery } from "@tanstack/react-query";
@@ -42,7 +42,7 @@ export function useCustomAgents(filterValidFiles = false) {
return {
customAgents: filterValidFiles
- ? customAgentsSignal.value.filter(isValidCustomAgentFile)
+ ? customAgentsSignal.value.filter(isValidCustomAgent)
: customAgentsSignal.value,
isLoading: false,
};
diff --git a/packages/vscode/src/integrations/webview/vscode-host-impl.ts b/packages/vscode/src/integrations/webview/vscode-host-impl.ts
index 59811c811..dd28bacea 100644
--- a/packages/vscode/src/integrations/webview/vscode-host-impl.ts
+++ b/packages/vscode/src/integrations/webview/vscode-host-impl.ts
@@ -69,6 +69,7 @@ import {
getTaskDisplayTitle,
} from "@getpochi/common/vscode-webui-bridge";
import type {
+ CustomAgent,
PreviewReturnType,
PreviewToolFunctionType,
ToolFunctionType,
@@ -219,9 +220,11 @@ export class VSCodeHostImpl implements VSCodeHostApi, vscode.Disposable {
readEnvironment = async (options: {
isSubTask?: boolean;
webviewKind: "sidebar" | "pane";
+ taskId?: string;
}): Promise => {
const isSubTask = options.isSubTask ?? false;
const webviewKind = options.webviewKind;
+ const taskId = options.taskId;
const { files, isTruncated } = this.cwd
? await listWorkspaceFiles({
cwd: this.cwd,
@@ -269,6 +272,7 @@ export class VSCodeHostImpl implements VSCodeHostApi, vscode.Disposable {
info: {
...systemInfo,
customRules,
+ taskId,
},
};
@@ -911,7 +915,7 @@ export class VSCodeHostImpl implements VSCodeHostApi, vscode.Disposable {
};
readCustomAgents = async (): Promise<
- ThreadSignalSerialization
+ ThreadSignalSerialization<(CustomAgent | CustomAgentFile)[]>
> => {
return ThreadSignal.serialize(this.customAgentManager.agents);
};
diff --git a/packages/vscode/src/lib/custom-agent.ts b/packages/vscode/src/lib/custom-agent.ts
index 7a1f6764d..44b27f8b2 100644
--- a/packages/vscode/src/lib/custom-agent.ts
+++ b/packages/vscode/src/lib/custom-agent.ts
@@ -1,8 +1,9 @@
import * as os from "node:os";
import * as path from "node:path";
-import { getLogger } from "@getpochi/common";
+import { builtInCustomAgents, getLogger } from "@getpochi/common";
import { parseAgentFile } from "@getpochi/common/tool-utils";
import type { CustomAgentFile } from "@getpochi/common/vscode-webui-bridge";
+import type { CustomAgent } from "@getpochi/tools";
import { signal } from "@preact/signals-core";
import { uniqueBy } from "remeda";
import { Lifecycle, injectable, scoped } from "tsyringe";
@@ -44,7 +45,7 @@ async function readAgentsFromDir(dir: string): Promise {
export class CustomAgentManager implements vscode.Disposable {
private disposables: vscode.Disposable[] = [];
- readonly agents = signal([]);
+ readonly agents = signal<(CustomAgent | CustomAgentFile)[]>([]);
constructor(private readonly workspaceScope: WorkspaceScope) {
this.initWatchers();
@@ -97,7 +98,9 @@ export class CustomAgentManager implements vscode.Disposable {
private async loadAgents() {
try {
- const allAgents: CustomAgentFile[] = [];
+ const allAgents: (CustomAgent | CustomAgentFile)[] = [
+ ...builtInCustomAgents,
+ ];
if (this.cwd) {
const projectAgentsDir = path.join(this.cwd, ".pochi", "agents");
const cwd = this.cwd;