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
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

import { strict as assert } from 'node:assert';
import { describe, it } from 'node:test';
import { DEEP_RESEARCH_SESSION_LABEL } from '@maka/core/explore-agent';
import { DEEP_RESEARCH_SESSION_LABEL } from '@maka/core/deep-research';

import { DEFAULT_SESSION_NAME } from '@maka/core/session-name';

Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/main/create-session-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import type { OrchestrationMode } from '@maka/core/orchestration';

import type { PermissionMode } from '@maka/core/permission';

import type { SessionStartMode } from '@maka/core/explore-agent';
import type { SessionStartMode } from '@maka/core/deep-research';
import { DEFAULT_SESSION_NAME } from '@maka/core/session-name';

import { isChatDefaultPermissionMode } from '@maka/core/settings';
Expand All @@ -52,7 +52,7 @@ import { isCollaborationMode } from '@maka/core/collaboration';

import { isOrchestrationMode } from '@maka/core/orchestration';

import { isSessionStartMode } from '@maka/core/explore-agent';
import { isSessionStartMode } from '@maka/core/deep-research';

/**
* `unknown`, because this is an IPC boundary and the renderer's type is a
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/renderer/app-shell-command-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import { useMemo, useRef } from "react";
import type { LlmConnection } from '@maka/core/llm-connections';
import type { PermissionMode } from '@maka/core/permission';
import type { SessionStartMode } from '@maka/core/explore-agent';
import type { SessionStartMode } from '@maka/core/deep-research';
import type { SessionSummary, StoredMessage } from '@maka/core/session';
import type { SettingsSection, ThemePreference } from '@maka/core/settings';
import type { UiLocale } from '@maka/core/ui-locale';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* under the License.
*/

import type { SessionStartMode } from '@maka/core/explore-agent';
import type { SessionStartMode } from '@maka/core/deep-research';
import type { UiLocale } from '@maka/core/ui-locale';
import type { NavSelection } from '@maka/ui';
import type { DesktopNewTaskTarget } from '../preload/bridge-contract.js';
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/renderer/chat-message-surface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

import { useMemo, useState, type ComponentProps, type ReactNode } from 'react';
import { isDeepResearchSession } from '@maka/core/explore-agent';
import { isDeepResearchSession } from '@maka/core/deep-research';
import { type LlmConnection, type ProviderType } from '@maka/core/llm-connections';
import { type OnboardingState } from '@maka/core/onboarding';
import { type SettingsSection } from '@maka/core/settings';
Expand Down
2 changes: 1 addition & 1 deletion docs/archive/expert-team-implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ guards: isValidPluginFolderName(无 ../\/前导.); BLOCKED{员工管理,招
2. **磁盘 artifact + JSON 指针 fan-in(两家都用)**:member 把重产物落盘,只回小 JSON 指针,orchestrator 上下文保持极小。maka 实现专家团时必须这样,否则 lead 上下文爆炸。

## C3. maka 落地要点(详见 [expert-team-plan.md](expert-team-plan.md))
- **单专家** = `mode:expert:<id>` 标签 + 人格 fragment(照抄 Deep Research 的 `explore-agent.ts` 路径),人格经 `childInstruction` 边界注入(继承权限/隐私/工作区)。`defaultInitPrompt` 学 WorkBuddy 只 pre-fill composer(P0 简单)。
- **单专家** = `mode:expert:<id>` 标签 + 人格 fragment(照抄 Deep Research 的 `deep-research.ts` 路径),人格经 `childInstruction` 边界注入(继承权限/隐私/工作区)。`defaultInitPrompt` 学 WorkBuddy 只 pre-fill composer(P0 简单)。
- **专家团** = lead 用 `mode:expert:<teamId>` + orchestrator 人格,member 注册进 `agent-catalog.ts` 的 `BUILTIN_AGENT_DEFINITIONS`(各带窄 `tools`),lead 用现有 `agent_spawn`/`spawnChildAgent` 派生(星型,非隔离,单轮 fan-out + await fan-in,回指针)。**先不做 Teams mailbox**。
- **专家中心** = 克隆 `skills-panel.tsx`(市场/内置/已安装)+ `managed-skill-sources.ts`(加 `sourceType:'remote'` 拉 COS 式 manifest,`contentSha256` 已就绪)。
- **数字同事** = P2 持久化外壳(雇佣专家 + 昵称/头像/仓库/资料库/模型),IM 绑定/云端是最重的 P3+,需评估是否值得(WorkBuddy 靠云后端 + IM CLI 子进程,成本高)。
2 changes: 1 addition & 1 deletion docs/archive/expert-team-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ QoderWork **没有**命名人格选择器。它的三层值得参考:

| 关注点 | 复用/扩展 | 位置 |
|---|---|---|
| 专家**人格注入** | `mode:` 标签 + prompt fragment(照抄 Deep Research) | `apps/desktop/src/main/system-prompt-main.ts`(已有 `childInstruction` seam);`packages/core/src/explore-agent.ts`(`mode:deep_research` 先例) |
| 专家**人格注入** | `mode:` 标签 + prompt fragment(照抄 Deep Research) | `apps/desktop/src/main/system-prompt-main.ts`(已有 `childInstruction` seam);`packages/core/src/deep-research.ts`(`mode:deep_research` 先例) |
| 专家=**带工具作用域的专业 agent** | 扩展 `BUILTIN_AGENT_DEFINITIONS`(每条已带 `systemPrompt`) | `packages/runtime/src/agent-catalog.ts`、`subagent-tools.ts`(`agent_spawn`/`SessionManager.spawnChildAgent`) |
| 专家**目录 + 按需安装** | 克隆 managed/bundled 技能目录 | `apps/desktop/src/main/managed-skill-sources.ts`、`bundled-skill-catalog.generated.ts`、`skills.ts`(install→`skill.lock.json`→baseline→update diff,PR #842) |
| 专家**定义文件格式** | 复用 SKILL.md frontmatter 解析 | `packages/runtime/src/skills.ts`(`parseSkillFrontMatter`) |
Expand Down
3 changes: 1 addition & 2 deletions docs/astryx-surface-file-inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Each row is one on-disk product surface file. Regenerated inventory must stay in

Wiki bar: Design Conventions · API Use-the-System · Theming · Container Padding.

**Totals:** 224 files — blocker 0, polish 1, aligned 223.
**Totals:** 223 files — blocker 0, polish 1, aligned 222.

## Exclusions (explicit)

Expand Down Expand Up @@ -242,7 +242,6 @@ Wiki bar: Design Conventions · API Use-the-System · Theming · Container Paddi
| `packages/ui/src/titlebar-session-identity.tsx` | shell-chrome-or-panel | BreadcrumbItem, Breadcrumbs | aligned — uses Astryx (BreadcrumbItem, Breadcrumbs) | aligned |
| `packages/ui/src/toast.tsx` | ui-composition | Button, HStack, Text, VStack | aligned — uses Astryx (Button, HStack, Text, VStack) | aligned |
| `packages/ui/src/tool-activity.tsx` | ui-composition | Banner, Button, ChatToolCalls, List, ListItem, Text | aligned — uses Astryx (Banner, Button, ChatToolCalls, List, ListItem, Text) | aligned |
| `packages/ui/src/tool-activity/agent-preview.tsx` | ui-composition | Button | aligned — uses Astryx (Button) | aligned |
| `packages/ui/src/tool-activity/diff-code-preview.tsx` | ui-composition | none | aligned — no raw controls; no Astryx JSX usage | aligned |
| `packages/ui/src/tool-activity/tool-code-block.tsx` | ui-composition | none | aligned — no raw controls; no Astryx JSX usage | aligned |
| `packages/ui/src/tool-activity/tool-result-preview.tsx` | ui-composition | Button | aligned — uses Astryx (Button) | aligned |
Expand Down
1 change: 0 additions & 1 deletion docs/astryx-surface-file-inventory.paths
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,6 @@ packages/ui/src/task-ledger-panel.tsx
packages/ui/src/titlebar-session-identity.tsx
packages/ui/src/toast.tsx
packages/ui/src/tool-activity.tsx
packages/ui/src/tool-activity/agent-preview.tsx
packages/ui/src/tool-activity/diff-code-preview.tsx
packages/ui/src/tool-activity/tool-code-block.tsx
packages/ui/src/tool-activity/tool-result-preview.tsx
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/__tests__/pi-transcript.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4292,8 +4292,8 @@ describe('Maka Pi TUI transcript', () => {
state,
event({
type: 'tool_start',
toolUseId: 'explore-intent',
toolName: 'ExploreAgent',
toolUseId: 'grep-intent',
toolName: 'Grep',
args: undefined,
intent: ' inspect render entry with sk-1234567890abcdef ',
}),
Expand Down
7 changes: 0 additions & 7 deletions packages/cli/src/pi-transcript-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,6 @@ export function formatToolResultContent(content: ToolResultContent): string {
].join('\n\n');
case 'web_search_error':
return content.message;
case 'explore_agent':
return (
content.report ??
content.summary ??
content.message ??
`Inspected ${content.filesInspected} files`
);
case 'subagent':
return content.summary;
case 'agent_swarm': {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"./deep-research-client-progress": "./dist/deep-research-client-progress.js",
"./daily-review": "./dist/daily-review.js",
"./work-board": "./dist/work-board.js",
"./explore-agent": "./dist/explore-agent.js",
"./deep-research": "./dist/deep-research.js",
"./long-term-memory": "./dist/long-term-memory.js",
"./local-memory": "./dist/local-memory.js",
"./web-search": "./dist/web-search.js",
Expand Down
31 changes: 31 additions & 0 deletions packages/core/src/__tests__/deep-research.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import assert from 'node:assert/strict';
import { test } from 'node:test';
import { buildDeepResearchSystemPromptFragment } from '../deep-research.js';

test('Deep Research directs inspection through the standard read-only tool surface', () => {
const prompt = buildDeepResearchSystemPromptFragment();

for (const toolName of ['Read', 'Glob', 'Grep', 'WebSearch']) {
assert.match(prompt, new RegExp(`\\b${toolName}\\b`));
}
assert.doesNotMatch(prompt, /ExploreAgent/);
});
119 changes: 119 additions & 0 deletions packages/core/src/__tests__/tool-result-record-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,125 @@ describe('retired permission modes in stored subagent results', () => {
});
});

describe('retired ExploreAgent results in stored transcripts', () => {
const stored = {
kind: 'explore_agent',
ok: true,
mode: 'read_only',
objective: 'Trace the session lifecycle.',
roots: ['packages/runtime'],
queries: ['SessionManager'],
filesInspected: 3,
filesSkipped: 1,
bytesRead: 512,
progress: ['Inspected the runtime entry point.'],
candidateFiles: [],
matches: [],
notes: [],
report: 'SessionManager owns the lifecycle.',
} as const;

test('folds the legacy result to ordinary historical text at every persisted read boundary', () => {
const expected = { kind: 'text', text: 'SessionManager owns the lifecycle.' };

assert.deepEqual(
decodePersistedToolResultContent(
markPersisted<ToolResultContent>(stored as unknown as ToolResultContent),
),
expected,
);
assert.deepEqual(toolResultContent(decodePersistedMessage(storedToolResult(stored))), expected);
});

test('accepts the earliest persisted shape before progress was added', () => {
const earliest = {
kind: 'explore_agent',
ok: true,
mode: 'read_only',
objective: 'Trace the session lifecycle.',
roots: ['packages/runtime'],
queries: ['SessionManager'],
filesInspected: 3,
filesSkipped: 1,
bytesRead: 512,
candidateFiles: [],
matches: [],
notes: [],
} as const;
const expected = { kind: 'text', text: 'Inspected 3 files' };

assert.deepEqual(
decodePersistedToolResultContent(
markPersisted<ToolResultContent>(earliest as unknown as ToolResultContent),
),
expected,
);
assert.deepEqual(
toolResultContent(decodePersistedMessage(storedToolResult(earliest))),
expected,
);
});

test('uses a non-empty failure summary when the legacy report is empty', () => {
const failed = {
...stored,
ok: false,
terminalStatus: 'failed',
report: '',
summary: '未完成:目标无效。',
reason: 'invalid_objective',
message: '目标无效。',
} as const;

assert.deepEqual(
decodePersistedToolResultContent(
markPersisted<ToolResultContent>(failed as unknown as ToolResultContent),
),
{ kind: 'text', text: '未完成:目标无效。' },
);
});

test('ignores retired structured detail after establishing legacy provenance', () => {
const malformedDetails = {
...stored,
report: undefined,
progress: { invalid: true },
matches: 'not an array',
filesInspected: undefined,
removedInLaterVersions: true,
};

assert.deepEqual(
decodePersistedToolResultContent(
markPersisted<ToolResultContent>(malformedDetails as unknown as ToolResultContent),
),
{ kind: 'text', text: 'Historical repository scan result' },
);
});

test('requires stable legacy provenance at persisted read boundaries', () => {
assert.throws(
() =>
decodePersistedToolResultContent(
markPersisted<ToolResultContent>({
kind: 'explore_agent',
ok: true,
mode: 'write_enabled',
} as unknown as ToolResultContent),
),
/Invalid tool result content/,
);
});

test('rejects the retired result kind at canonical live boundaries', () => {
assert.throws(() => decodeCanonicalToolResultContent(stored), /Invalid tool result content/);
assert.throws(
() => decodeCanonicalMessage(storedToolResult(stored)),
/Invalid tool result content/,
);
});
});

function storedToolResult(content: unknown) {
return {
type: 'tool_result',
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/deep-research-client-progress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* under the License.
*/

import { buildDeepResearchImplementationPrompt } from './explore-agent.js';
import { buildDeepResearchImplementationPrompt } from './deep-research.js';
import {
DEEP_RESEARCH_CLIENT_IMPLEMENTATION_PROMPT_MAX_BYTES,
DEEP_RESEARCH_CLIENT_OBJECTIVE_MAX_BYTES,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,7 @@
* under the License.
*/

/**
* Read-only deep research mode (external reference design).
*
* Deep research is visible and bounded. The session profile pins
* permissionMode=explore and may use the read-only ExploreAgent tool for
* scoped local investigation; it is not a hidden autonomous writer.
*/
/** Read-only Deep Research session semantics and prompt contract. */

import type { DeepResearchRun } from './deep-research-run.js';
import type { PermissionMode } from './permission.js';
Expand Down Expand Up @@ -231,24 +225,12 @@ export function buildDeepResearchImplementationPrompt(run: DeepResearchRun): str
);
}

export function buildDeepResearchSystemPromptFragment(
options: { readonly exploreAgentAvailable?: boolean } = {},
): string {
const exploreAgentAvailable = options.exploreAgentAvailable ?? true;
export function buildDeepResearchSystemPromptFragment(): string {
return [
'Deep research mode is active for this session.',
'',
'Mode contract:',
exploreAgentAvailable
? '- Inspect first. Prefer Read, Glob, Grep, WebSearch, and ExploreAgent.'
: '- Inspect first. Prefer Read, Glob, Grep, and WebSearch.',
...(exploreAgentAvailable
? [
'- Use ExploreAgent only for a separate, self-contained local investigation that benefits from a bounded read-only worker. Keep synthesis and final judgment in the main thread.',
'- Do not use ExploreAgent just because it is available. If the next step is a known file, a specific symbol, package scripts, test setup, config, or 1-3 obvious files, inspect directly in the main thread.',
'- When using ExploreAgent, bound the prompt with a goal, relevant paths or keywords, what to ignore, a stopping condition, and exactly what evidence the worker should return.',
]
: []),
'- Inspect first. Prefer Read, Glob, Grep, and WebSearch.',
'- Do not write, edit, delete, move, or rename user project files; do not install, run migrations, start services, or send network requests unless the user explicitly leaves research mode.',
'- The deep_research_* tools are the one write exception: they only update Maka-owned research artifacts and an append-only workspace ledger, never the user project.',
'- If implementation is needed, produce a concrete plan with files, risks, and verification commands instead of modifying files.',
Expand Down
39 changes: 0 additions & 39 deletions packages/core/src/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -812,45 +812,6 @@ export type ToolResultContent =
message: string;
credentialSource?: string;
}
| {
kind: 'explore_agent';
ok: boolean;
partial?: boolean;
terminalStatus?: 'completed' | 'completed_empty' | 'failed' | 'canceled' | 'canceled_partial';
mode: 'read_only';
objective: string;
roots: string[];
queries: string[];
ignoredPaths?: string[];
stoppingCondition?: string;
limitReasons?: ReadonlyArray<
'candidate_budget' | 'file_budget' | 'match_budget' | 'byte_budget'
>;
filesDiscovered?: number;
filesInspected: number;
filesSkipped: number;
sensitiveFilesSkipped?: number;
bytesRead: number;
startedAt?: number;
completedAt?: number;
durationMs?: number;
progress: string[];
recentEvents?: ReadonlyArray<{ type: string; at: number; message: string }>;
evidence?: ReadonlyArray<{
type: 'match' | 'candidate';
path: string;
line?: number;
label: string;
score?: number;
}>;
summary?: string;
report?: string;
candidateFiles: ReadonlyArray<{ path: string; score: number; reasons: string[] }>;
matches: ReadonlyArray<{ path: string; line: number; query: string; snippet: string }>;
notes: string[];
reason?: 'invalid_objective' | 'invalid_root' | 'no_readable_roots' | 'aborted';
message?: string;
}
| {
kind: 'subagent';
childSessionId?: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/runtime-inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import type { PermissionMode } from './permission.js';
import type { ThinkingLevel } from './model-thinking.js';
import type { CollaborationMode } from './collaboration.js';
import type { OrchestrationMode, TurnOrchestration } from './orchestration.js';
import type { SessionStartMode } from './explore-agent.js';
import type { SessionStartMode } from './deep-research.js';
import type { SubagentWorkspaceBinding } from './subagent-workspace.js';
import type { ToolMode } from './tool-mode.js';
import type { TurnOrigin } from './turn-origin.js';
Expand Down
Loading