Skip to content
Open
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
24 changes: 24 additions & 0 deletions .pochi/agents/walkthroughs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
name: walkthroughs
description: Create or update walkthrough summaries for a task when the user requests a walkthrough or project recap.
tools: readFile, writeToFile, listFiles
---

You are a walkthrough authoring agent. Your job is to produce a concise Markdown walkthrough that helps a new reader get up to speed with the work completed in a task.

When invoked:
1. Identify the task id and target path. If the prompt provides an absolute path, use it; otherwise use `pochi/walkthroughs/$taskId.md`.
2. Review the conversation and tool outputs for requirements and actual changes.
3. Summarize key work items, notable file changes, and any commands run.
4. Include outcomes and any remaining follow-ups or known gaps.
5. If references to screenshots or recordings are available, include them as links or notes.
6. Write the walkthrough to the target path using `writeToFile`.

Output rules:
- Write Markdown to the target file only (use `writeToFile`).
- After finishing, call `attemptCompletion` with: "Walkthrough created at <path>".
- Do not include any other response text outside the tool call.
- If you need to check whether the walkthrough file exists, try `readFile` on the target path; if it fails, proceed as a new file.
- Prefer short sections with bullets over long paragraphs.
- Keep it concise and actionable.
- If an existing walkthrough file is present, append an "Update" section rather than overwriting.
5 changes: 5 additions & 0 deletions packages/common/src/base/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ export const KnownTags = [
] as const;
export const CompactTaskMinTokens = 50_000;

// Built-in agent names
export const WALKTHROUGH_AGENT_NAME = "walkthroughs";
export const EXPLORE_AGENT_NAME = "explore";
export const DEBUGGER_AGENT_NAME = "debugger";

export const WorkspaceWorkflowPathSegments = [".pochi", "workflows"];

export const DefaultContextWindow = 100_000;
Expand Down
5 changes: 5 additions & 0 deletions packages/common/src/base/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ export { prompts } from "./prompts";

export { SocialLinks } from "./social";
export * as constants from "./constants";
export {
WALKTHROUGH_AGENT_NAME,
EXPLORE_AGENT_NAME,
DEBUGGER_AGENT_NAME,
} from "./constants";

export {
Environment,
Expand Down
3 changes: 3 additions & 0 deletions packages/common/src/vscode-webui-bridge/webview-stub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ const VSCodeHostStub = {
openExternal: (_uri: string): Promise<void> => {
return Promise.resolve();
},
checkFileExists: async (_path: string): Promise<boolean> => {
return Promise.resolve(false);
},
readMinionId: async () => {
return Promise.resolve(null);
},
Expand Down
7 changes: 7 additions & 0 deletions packages/common/src/vscode-webui-bridge/webview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,13 @@ export interface VSCodeHostApi {
*/
openExternal(uri: string): Promise<void>;

/**
* Checks if a file exists at the given path.
* @param path - The file path to check.
* @returns A promise that resolves to true if the file exists, false otherwise.
*/
checkFileExists(path: string): Promise<boolean>;

/**
* Saves a checkpoint with the given message.
* @param message - The message to save as a checkpoint.
Expand Down
25 changes: 25 additions & 0 deletions packages/livekit/src/chat/middlewares/new-task-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import type {
LanguageModelV2StreamPart,
} from "@ai-sdk/provider";
import { safeParseJSON } from "@ai-sdk/provider-utils";
import { WALKTHROUGH_AGENT_NAME } from "@getpochi/common";
import { type CustomAgent, newTaskInputSchema } from "@getpochi/tools";
import type { Store } from "@livestore/livestore";
import { InvalidToolInputError } from "ai";
import { makeMessagesQuery } from "../../livestore/default-queries";
import { events } from "../../livestore/default-schema";

export function createNewTaskMiddleware(
Expand All @@ -14,6 +16,17 @@ export function createNewTaskMiddleware(
parentTaskId: string,
customAgents?: CustomAgent[],
): LanguageModelV2Middleware {
const builtinAgentDefaults: Record<
string,
{
inheritParentMessages?: boolean;
}
> = {
[WALKTHROUGH_AGENT_NAME]: {
inheritParentMessages: true,
},
};

return {
middlewareVersion: "v2",
transformParams: async ({ params }) => {
Expand Down Expand Up @@ -95,13 +108,25 @@ export function createNewTaskMiddleware(
args._meta = {
uid,
};
const agentType = args.agentType ?? "";
const shouldInheritParentMessages =
args.inheritParentMessages ??
builtinAgentDefaults[agentType]?.inheritParentMessages ??
false;
const parentMessages = shouldInheritParentMessages
? store.query(makeMessagesQuery(parentTaskId)).map((x) => ({
...x.data,
id: crypto.randomUUID(),
}))
: [];
store.commit(
events.taskInited({
id: uid,
cwd,
parentId: parentTaskId,
createdAt: new Date(),
initMessages: [
...parentMessages,
{
id: crypto.randomUUID(),
role: "user",
Expand Down
3 changes: 3 additions & 0 deletions packages/livekit/src/chat/walkthrough.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function getWalkthroughPath(taskId: string): string {
return `pochi/walkthroughs/${taskId}.md`;
}
1 change: 1 addition & 0 deletions packages/livekit/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export type {

export const StoreBlobProtocol = "store-blob:";
export { processContentOutput, fileToUri } from "./store-blob";
export { getWalkthroughPath } from "./chat/walkthrough";
4 changes: 4 additions & 0 deletions packages/tools/src/new-task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ export const inputSchema = z.object({
.string()
.optional()
.describe("The type of the specialized agent to use for the task."),
inheritParentMessages: z
.boolean()
.optional()
.describe("Whether to inherit the parent task's messages."),
_meta: z
.object({
uid: z.string().describe("A unique identifier for the task."),
Expand Down
6 changes: 6 additions & 0 deletions packages/vscode-webui/src/components/message/message-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const MessageList: React.FC<{
showLoader?: boolean;
forkTask?: (commitId: string, messageId?: string) => Promise<void>;
hideCheckPoint?: boolean;
taskId?: string;
}> = ({
messages: renderMessages,
isLoading,
Expand All @@ -58,6 +59,7 @@ export const MessageList: React.FC<{
showLoader = true,
forkTask,
hideCheckPoint,
taskId,
}) => {
const [debouncedIsLoading, setDebouncedIsLoading] = useDebounceState(
isLoading,
Expand Down Expand Up @@ -139,6 +141,7 @@ export const MessageList: React.FC<{
hideCheckPoint={hideCheckPoint}
latestCheckpoint={latestCheckpoint}
lastCheckpointInMessage={lastCheckpointInMessage}
taskId={taskId}
/>
))}
</div>
Expand Down Expand Up @@ -200,6 +203,7 @@ function Part({
hideCheckPoint,
latestCheckpoint,
lastCheckpointInMessage,
taskId,
}: {
role: Message["role"];
partIndex: number;
Expand All @@ -212,6 +216,7 @@ function Part({
hideCheckPoint?: boolean;
latestCheckpoint: string | null;
lastCheckpointInMessage: string | undefined;
taskId?: string;
}) {
const paddingClass = partIndex === 0 ? "" : "mt-2";
if (part.type === "text") {
Expand Down Expand Up @@ -261,6 +266,7 @@ function Part({
isLoading={isLoading}
changes={getToolCallCheckpoint(part, messages)}
messages={messages}
taskId={taskId}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface ChatAreaProps {
hideEmptyPlaceholder?: boolean;
forkTask?: (commitId: string, messageId?: string) => Promise<void>;
hideCheckPoint?: boolean;
taskId?: string;
}

export function ChatArea({
Expand All @@ -24,6 +25,7 @@ export function ChatArea({
hideEmptyPlaceholder,
forkTask,
hideCheckPoint,
taskId,
}: ChatAreaProps) {
const resourceUri = useResourceURI();
return (
Expand All @@ -44,6 +46,7 @@ export function ChatArea({
className={className}
forkTask={forkTask}
hideCheckPoint={hideCheckPoint}
taskId={taskId}
/>
</>
);
Expand Down
1 change: 1 addition & 0 deletions packages/vscode-webui/src/features/chat/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ function Chat({ user, uid, info }: ChatProps) {
hideEmptyPlaceholder={!isTaskWithoutContent}
forkTask={task?.cwd ? forkTask : undefined}
hideCheckPoint={isSubTask}
taskId={uid}
/>
<div className={ChatToolbarContainerClassName}>
<ChatToolbar
Expand Down
Loading