import { For, createSignal, createMemo } from "solid-js";
import { useNavigate, useParams } from "@tanstack/solid-router";
import { getEmailsForMailbox } from "~/data/emails";
import { MailListItem } from "~/components/MailListItem";
export function MailList() {
const params = useParams({ strict: false }) as {
mailbox?: string;
id?: string;
};
const navigate = useNavigate();
const [query, setQuery] = createSignal("");
const mailbox = () => params.mailbox || "inbox";
const list = createMemo(() => {
const q = query().toLowerCase();
return getEmailsForMailbox(mailbox()).filter(
(e) =>
!q ||
e.subject.toLowerCase().includes(q) ||
e.snippet.toLowerCase().includes(q)
);
});
function open(id: string) {
navigate({
to: "/mail/$mailbox/$id",
params: { mailbox: mailbox(), id },
search: (prev) => prev,
});
}
return (
<For each={list()}>
{(e) => (
<div
role="listitem"
tabindex={0}
onClick={() => open(e.id)}
onKeyDown={(ev) => ev.key === "Enter" && open(e.id)}
class="mail-item"
data-selected={params.id === e.id ? "true" : undefined}
aria-selected={params.id === e.id ? "true" : undefined}
>
<div>
<div class="mail-item-subject truncate">{e.subject}</div>
<div class="mail-item-snippet truncate">{e.snippet}</div>
</div>
<time
class="text-xs muted"
datetime={e.date}
title={new Date(e.date).toLocaleString()}
>
{new Date(e.date).toLocaleDateString(undefined, {
month: "short",
day: "numeric",
})}
</time>
</div>
<MailListItem
email={e}
isSelected={params.id === e.id}
onOpen={open}
/>
)}
</For>
);
}
import type { Email } from "~/types";
interface MailListItemProps {
email: Email;
isSelected: boolean;
onOpen: (id: string) => void;
}
export function MailListItem(props: MailListItemProps) {
return (
<div
role="listitem"
tabindex={0}
onClick={() => props.onOpen(props.email.id)}
onKeyDown={(ev) => ev.key === "Enter" && props.onOpen(props.email.id)}
class="mail-item"
data-selected={props.isSelected ? "true" : undefined}
aria-selected={props.isSelected ? "true" : undefined}
>
<div>
<div class="mail-item-subject truncate">{props.email.subject}</div>
<div class="mail-item-snippet truncate">{props.email.snippet}</div>
</div>
<time
class="text-xs muted"
datetime={props.email.date}
title={new Date(props.email.date).toLocaleString()}
>
{new Date(props.email.date).toLocaleDateString(undefined, {
month: "short",
day: "numeric",
})}
</time>
</div>
);
- 创建新的
MailListItem 处理单个邮件列表项渲染的组件 - 从
MailList 中提取邮件项 JSX 和逻辑到新的MailListItem 组件中 - 更新
MailList 以使用新的MailListItem 组件中 - 构建项目以验证更改是否正确编译
- 测试应用程序以确保功能保持完整
- 创建了一个用于渲染单个邮件列表项的可重用组件
- 接受
email ,isSelected 和onSelect props - 保持所有辅助功能(ARIA 角色、键盘导航)
- 保留样式和交互行为
- 通过删除内联邮件项渲染逻辑进行了简化
- 现在使用
MailListItem 组件并清晰地传递 props - 降低了组件复杂性并提高了可读性
- ✅ 构建成功
- ✅ 所有功能运行正常(过滤、选择、导航)
- ✅ 保留了键盘辅助功能(Enter 键导航)
- ✅ 视觉选择状态工作正常
为您构建的智能体
将任务移交给能够自主规划、进行代码更改、运行命令并迭代直到工作完成的 AI 智能体。
例如,分配一个基于 CLI 的智能体在后台进行分类并修复错误,与另一个智能体交互以在集成浏览器中使用实时验证来实现功能,并将主页重构委托给一个云智能体,该智能体为您团队的审查打开一个拉取请求。
开始使用代理package http
import (
"io"
"log/slog"
"mime/multipart"
"net/http"
"strings"
)
type BatchItemResult struct {
Name string `json:"name"`
Metadata *struct {
Format string `json:"format"`
Width int `json:"width"`
Height int `json:"height"`
Bytes int `json:"bytes"`
} `json:"metadata,omitempty"`
Error string `json:"error,omitempty"`
}
type BatchResponse struct {
Results []*BatchItemResult `json:"results"`
Count int `json:"count"`
Success int `json:"success"`
Failed int `json:"failed"`
}
// handleProcessBatch processes multiple uploaded images (multipart/form-data) under the field name "files".
// It returns metadata for each image or an error per item without failing the whole batch unless the request is malformed.
func (s *Server) handleProcessBatch(w http.ResponseWriter, r *http.Request) {
// Enforce max body size overall.
r.Body = http.MaxBytesReader(w, r.Body, s.cfg.MaxUploadBytes)
if ct := r.Header.Get("Content-Type"); !strings.HasPrefix(ct, "multipart/form-data") {
s.writeJSON(w, http.StatusBadRequest, map[string]string{"error": "content type must be multipart/form-data"})
return
}
if err := r.ParseMultipartForm(s.cfg.MaxUploadBytes); err != nil {
status := http.StatusBadRequest
if strings.Contains(err.Error(), "request body too large") {
status = http.StatusRequestEntityTooLarge
}
s.writeJSON(w, status, map[string]string{"error": "invalid multipart form: " + err.Error()})
return
}
// Accept files under the key "files". If absent, attempt to fallback to any file parts.
var fileHeaders []*multipart.FileHeader
if r.MultipartForm != nil && len(r.MultipartForm.File["files"]) > 0 {
fileHeaders = r.MultipartForm.File["files"]
} else if r.MultipartForm != nil {
// Fallback: gather all files across keys.
for _, fhs := range r.MultipartForm.File {
fileHeaders = append(fileHeaders, fhs...)
}
}
if len(fileHeaders) == 0 {
s.writeJSON(w, http.StatusBadRequest, map[string]string{"error": "no files provided (expect key 'files')"})
return
}
resp := &BatchResponse{Results: make([]*BatchItemResult, 0, len(fileHeaders))}
for _, fh := range fileHeaders {
item := &BatchItemResult{Name: fh.Filename}
f, err := fh.Open()
if err != nil {
item.Error = "open file: " + err.Error()
resp.Results = append(resp.Results, item)
resp.Failed++
continue
}
data, err := io.ReadAll(f)
_ = f.Close()
if err != nil {
item.Error = "read file: " + err.Error()
resp.Results = append(resp.Results, item)
resp.Failed++
continue
}
meta, err := s.proc.ExtractMetadata(data)
if err != nil {
item.Error = err.Error()
resp.Results = append(resp.Results, item)
resp.Failed++
continue
}
// Copy into anonymous struct to decouple from internal type if it changes.
item.Metadata = &struct {
Format string `json:"format"`
Width int `json:"width"`
Height int `json:"height"`
Bytes int `json:"bytes"`
}{Format: meta.Format, Width: meta.Width, Height: meta.Height, Bytes: meta.Bytes}
resp.Results = append(resp.Results, item)
resp.Success++
}
resp.Count = len(resp.Results)
s.log.LogAttrs(r.Context(), slog.LevelInfo, "batch processed", slog.Int("count", resp.Count), slog.Int("success", resp.Success), slog.Int("failed", resp.Failed))
s.writeJSON(w, http.StatusOK, resp)
}
创建待办事项列表
我从创建待办事项列表开始,管理诸如读取现有服务器和处理器代码、设计批量端点契约以及使用处理程序实现新文件等任务。我打算将处理程序连接到服务器路由中,并可能为批量端点添加一个最小化的测试,尽管这是可选的。我还计划在之后运行测试并构建所有内容。让我们执行它!正在改进文件处理...
我可以修改 server.go,但他们要求创建一个新文件。所以我需要创建一个路由,让我们称之为 /process/batch。我将强制执行最大正文大小,并确保内容类型为 multipart/form-data。接下来,我将解析表单并遍历 form.File["files"]。 对于每个 FileHeader,我将打开它并读取字节,然后调用 ExtractMetadata 来收集结果。最后,我将返回一个结构化的 JSON 响应并处理无文件和最大批量限制的边缘情况。 我认为这可能不是绝对必要的,但我正在考虑通过使用 sync.WaitGroup 来按顺序处理每个文件,同时限制并发量来做一个小的改进。这将使初始提交更简单。我需要添加代码文件并导入内部图像引用别名。 接下来,我将查看 tests/image_processor_test.go 中的现有测试,以查看样式并确定我是否应该为批量处理程序创建一个新的测试文件。我将通读该文件,然后更新待办事项状态,将第一项和第二项标记为已完成。为 HTTP 测试做准备
我需要运行一个 HTTP 测试,但我注意到当前的测试包在“tests”中,而不是在主模块内。为了进行 HTTP 测试,我必须设置一些东西,例如配置、处理器、记录器和服务器,并发送一个多部分请求。我的下一步是检查 config.go 中的配置,以了解我需要包含哪些必填字段。让我们深入研究一下!管理更新和补丁
我需要使用 manage_todo_list 来保持一切井井有条,确保我不会遗漏任何任务。一旦完成,我就可以继续应用补丁。这将涉及添加一个新文件并对 server.go 进行编辑。我想确保在这个过程中一切都清晰准确,以避免在此过程中出现任何错误。让我们继续前进!实现更新和测试
我已将设计契约标记为已完成,接下来需要实施更新。我将继续管理待办事项列表并应用补丁来添加文件并更新 server.go。看来我可能需要在 server.go 中为 /process/batch 添加一个路由,并实现一个新文件 internal/http/batch.go。编写代码后,我将添加一个测试文件,使用 go test 运行测试,并使用 run_in_terminal 命令。让我们开始吧!-
server.go : 注册了新路由 POST /process/batch。 batch.go : 新处理程序 handleProcessBatch,该处理程序-
- 接受 multipart/form-data。
- 读取 files 键下的多个文件(如果缺少 files,则回退到任何文件部分)。
- 返回每个文件的成功/错误,而不会导致整个批次失败。
- 汇总计数:总数、成功、失败。
-
batch_endpoint_test.go : 测试了正常路径(1 个有效 + 1 个无效文件)和缺少文件的错误情况。
- 添加可配置的每批最大文件数(例如通过配置)。
- 针对超大图像的有限内存流处理(处理 + 丢弃)。
- 具有工作池和上下文取消的可选并行处理。
- 在解码之前添加每个文件的大小验证。
- 支持非多部分客户端的基于 JSON 的批处理(URL 或 base64)。
任何智能体,任何模型
使用适合您工作流程的智能体工具。在本地或云端运行智能体,使用 Copilot 或 Claude 和 OpenAI 等第三方提供商。
从提供商提供的数十种模型中进行选择,从快速补全模型到高级推理模型。或者自带密钥以使用任何提供商的任何模型。
您的所有会话,一个视图
当多个智能体并行处理任务时保持高效。从单个视图跟踪您的所有智能体会话,无论它们在哪里运行。
快速筛选和监控会话,或深入了解单个智能体交互,无需切换到其他工具或终端。
您的规则,您的智能体
确保智能体遵循您的实践和团队工作流程。定义自定义指令、添加智能体技能或构建针对您的项目量身定制的自定义智能体。
通过 MCP 服务器连接到外部工具和服务,或安装智能体插件或扩展以扩展智能体的功能。
核心是一流的代码编辑器
十多年来,VS Code 一直是数百万开发者的首选编辑器。 AI 驱动的内联建议、智能补全和丰富的编辑体验使它在您自己编写代码时同样强大。
在同一个编辑器中,无缝切换智能体工作和手动编码。
开始使用 VS Codeimport numpy as np
import pandas as pd
iris_data = pd.read_csv("iris_dataset.csv")
def describe(species: str) -> pd.Series:
7
subset = data[data["species"] == species]
subset = iris_data[iris_data["species"] == species]
if subset.empty:
raise ValueError(f"{species} missing from sample")
return subset[["petal", "sepal"]].agg(["mean", "std"]).loc["mean"]
def summary():
13
for species in np.sort(data["species"].unique()):
for species in np.sort(iris_data["species"].unique()):
try:
stats = describe(species)
except ValueError:
print(f"{species}: no records")
continue
print(f"{species}: petal={stats['petal']:.2f} sepal={stats['sepal']:.2f}")
if __name__ == "__main__":
summary()
使用扩展进行编码
通过扩展和模型上下文协议 (MCP) 服务器中的工具扩展您的智能体。或者,构建您自己的扩展以支持您团队的独特场景。
使用任何语言编写代码
VS Code 支持几乎所有主流编程语言。包括 JavaScript、TypeScript、CSS 和 HTML 等多种内置语言,其他语言的扩展可以在 VS Code Marketplace 中找到。

JavaScript
TypeScript
Python
C#
C++
HTML
Java
JSON
PHP
Markdown
Powershell
YAML随时随地编码
在您最高效的地方编写代码,无论是连接到云端、远程仓库,还是通过 VS Code 网页版 (vscode.dev) 在浏览器中编写。
内置源代码控制为您提供开箱即用的 Git 支持。许多其他源代码控制提供商也可以通过扩展获得。
GitHub Codespaces 为任何活动提供云端开发环境 - 无论是长期项目,还是审阅拉取请求之类的短期任务。
通过丰富功能进行编码
编辑器还有很多功能。无论是使用内置功能还是丰富的扩展,总有一款适合您。