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
5 changes: 5 additions & 0 deletions .changeset/remove-now-template-variable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/agent-core-v2": patch
---

Remove the `${now}` variable from the system prompt template variable table.
1 change: 0 additions & 1 deletion docs/en/customization/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ Like the body of a regular agent file, SYSTEM.md is rendered as a template each
| `${cwd_listing}` | Listing of the working directory |
| `${os}` | Operating system kind |
| `${shell}` | Shell name and path, for example `bash (\`/bin/bash\`)` |
| `${now}` | Current time in ISO format |
| `${additional_dirs_info}` | Additional directories added to the workspace; empty when there are none |
| `${base_prompt}` | The default system prompt. Inside `SYSTEM.md` itself this is the built-in default; inside an agent file it is the effective default — the built-in default, or your `SYSTEM.md` override when present |
| `${plugin_sections}` | A complete Plugin Instructions block contributed by enabled plugins; empty when no enabled plugin contributes instructions |
Expand Down
1 change: 0 additions & 1 deletion docs/zh/customization/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ SYSTEM.md 是纯 Markdown 正文,不需要也不读取 Frontmatter。文件缺
| `${cwd_listing}` | 工作目录的文件列表 |
| `${os}` | 操作系统类型 |
| `${shell}` | Shell 名称与路径,例如 `bash (\`/bin/bash\`)` |
| `${now}` | 当前时间(ISO 格式) |
| `${additional_dirs_info}` | 加入工作区的额外目录信息;没有时为空 |
| `${base_prompt}` | 默认系统提示词。在 `SYSTEM.md` 中指内置默认提示词;在 Agent 文件中指有效默认提示词(内置默认,或存在时为你的 `SYSTEM.md` 覆盖) |
| `${plugin_sections}` | 已启用 plugin 提供的完整 Plugin Instructions 块;没有已启用 plugin 提供指令时为空 |
Expand Down
9 changes: 0 additions & 9 deletions packages/agent-core-v2/docs/state-manifest.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1316,15 +1316,6 @@ export interface AgentStateSnapshot {
readonly systemPrompt: string;
readonly environmentDisclosure?: /* EnvironmentDisclosureSnapshot — packages/agent-core-v2/src/app/agentProfileCatalog/agentProfileCatalog.ts */ {
readonly cwd: string;
readonly date: {
readonly disclosed: true;
readonly value: {
readonly localDate: string;
readonly timeZone: string;
};
} | {
readonly disclosed: false;
};
};
readonly renderGeneration: number;
readonly agentsMdPaths?: readonly string[];
Expand Down
2 changes: 0 additions & 2 deletions packages/agent-core-v2/docs/wire-manifest.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ interface ConfigUpdatePayload {
/** EnvironmentDisclosureSnapshot */
environmentDisclosure?: {
cwd: string;
date: { disclosed: true, value: { localDate: string, timeZone: string } } | { disclosed: false };
};
renderGeneration?: number;
agentsMdPaths?: string[];
Expand Down Expand Up @@ -495,7 +494,6 @@ interface ProfileBindPayload {
/** EnvironmentDisclosureSnapshot */
environmentDisclosure?: {
cwd: string;
date: { disclosed: true, value: { localDate: string, timeZone: string } } | { disclosed: false };
};
renderGeneration?: number;
agentsMdPaths?: string[];
Expand Down
6 changes: 0 additions & 6 deletions packages/agent-core-v2/src/agent/profile/profileService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import { IConfigService } from '#/app/config/config';
import type { LoopControl } from '#/agent/loop/configSection';
import { IAgentRuntimeService } from '#/agent/runtimeBinding/agentRuntime';
import { RuntimeWorkspaceView } from '#/runtime/runtimeWorkspaceView';
import { IHostClock } from '#/os/interface/hostClock';
import { ISessionContext } from '#/session/sessionContext/sessionContext';
import type { ToolSource } from '#/tool/toolContract';
import { ISessionWorkspaceContext } from '#/session/workspaceContext/workspaceContext';
Expand Down Expand Up @@ -150,7 +149,6 @@ export class AgentProfileService extends Disposable implements IAgentProfileServ
@IModelCatalog private readonly modelCatalog: IModelCatalog,
@IProtocolAdapterRegistry private readonly protocolAdapters: IProtocolAdapterRegistry,
@IAgentRuntimeService private readonly runtime: IAgentRuntimeService,
@IHostClock private readonly clock: IHostClock,
@ISessionContext private readonly sessionContext: ISessionContext,
@IBootstrapService private readonly bootstrap: IBootstrapService,
@ISessionWorkspaceContext private readonly workspace: ISessionWorkspaceContext,
Expand Down Expand Up @@ -816,16 +814,12 @@ export class AgentProfileService extends Disposable implements IAgentProfileServ
}
const skills = await this.resolveSkillListing();
const pluginSections = await this.resolvePluginSections();
const now = this.clock.now();
const timeZone = this.clock.timeZone();
return {
...base,
cwd: view.workDir,
osKind: env.osKind,
shellName: env.shellName,
shellPath: env.shellPath,
now: now.toISOString(),
timeZone,
skills,
pluginSections,
skillActive: this.isToolActiveForProfile(profile, 'Skill'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ export interface AgentProfileContext {
readonly osKind?: string;
readonly shellName?: string;
readonly shellPath?: string;
readonly now?: string;
readonly timeZone?: string;
readonly skills?: string;
readonly skillActive?: boolean;
readonly pluginSections?: string;
Expand All @@ -35,9 +33,6 @@ export interface AgentProfileContext {

export interface EnvironmentDisclosureSnapshot {
readonly cwd: string;
readonly date:
| { readonly disclosed: true; readonly value: { readonly localDate: string; readonly timeZone: string } }
| { readonly disclosed: false };
}

export interface SystemPromptRenderResult {
Expand Down Expand Up @@ -89,7 +84,7 @@ export function normalizeAgentProfile(input: AgentProfileInput): AgentProfile {
systemPrompt,
renderSystemPrompt: (context) => ({
text: systemPrompt(context),
environment: { cwd: context.cwd ?? '', date: { disclosed: false } },
environment: { cwd: context.cwd ?? '' },
}),
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ export function systemPromptVars(
os: context.osKind ?? '',
windows_notes: context.osKind === 'Windows' ? `\n\n${WINDOWS_NOTES}\n\n` : '',
shell: shellName.length > 0 ? `${shellName} (\`${shellPath}\`)` : '',
now: context.now ?? new Date().toISOString(),
cwd: context.cwd ?? '',
cwd_listing: context.cwdListing ?? '',
agents_md: context.agentsMd ?? '',
Expand Down Expand Up @@ -171,10 +170,7 @@ export function renderPromptTemplateResult(
}
return {
text: renderPrompt(template, vars),
environment: mergeEnvironmentDisclosure(
environmentForTemplate(template, context),
baseResult?.environment,
),
environment: mergeEnvironmentDisclosure(environmentForTemplate(context), baseResult?.environment),
};
}

Expand All @@ -188,55 +184,18 @@ export function renderSystemPromptResult(
...systemPromptVars(context, options),
role_additional: roleAdditional,
}),
environment: environmentForTemplate(SYSTEM_PROMPT_TEMPLATE, context),
environment: environmentForTemplate(context),
};
}

function environmentForTemplate(
template: string,
context: AgentProfileContext,
): EnvironmentDisclosureSnapshot {
const usesNow = template.includes('${now}');
const timeZone = context.timeZone ?? localTimeZone();
return {
cwd: context.cwd ?? '',
date: usesNow
? {
disclosed: true,
value: {
localDate: localDateKey(context.now, timeZone),
timeZone,
},
}
: { disclosed: false },
};
function environmentForTemplate(context: AgentProfileContext): EnvironmentDisclosureSnapshot {
return { cwd: context.cwd ?? '' };
}

function mergeEnvironmentDisclosure(
direct: EnvironmentDisclosureSnapshot,
base: EnvironmentDisclosureSnapshot | undefined,
): EnvironmentDisclosureSnapshot {
if (base === undefined) return direct;
return {
cwd: direct.cwd || base.cwd,
date: direct.date.disclosed ? direct.date : base.date,
};
}

function localDateKey(now: string | undefined, timeZone: string): string {
const date = now === undefined ? new Date() : new Date(now);
if (Number.isNaN(date.getTime())) return localDateKey(undefined, timeZone);
const parts = new Intl.DateTimeFormat('en-US', {
timeZone,
year: 'numeric',
month: '2-digit',
day: '2-digit',
}).formatToParts(date);
const part = (type: Intl.DateTimeFormatPartTypes): string =>
parts.find((candidate) => candidate.type === type)?.value ?? '';
return `${part('year')}-${part('month')}-${part('day')}`;
}

function localTimeZone(): string {
return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
return { cwd: direct.cwd || base.cwd };
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,6 @@ const dateChangeInjection = fromCallback(({
environment.cwd !== sessionContext.cwd
);
};
const dateFromProfile = (): DateDisclosure | undefined => {
if (!belongsToCurrentCwd()) return undefined;
const profileData = profile.data();
const date = profileData.environmentDisclosure?.date;
if (!date?.disclosed) return undefined;
return {
...date.value,
renderGeneration: profileData.renderGeneration ?? 0,
};
};
const registration = reminder.register<DateInjectionDisclosure>(
DATE_CHANGE_INJECTION_VARIANT,
({
Expand All @@ -95,13 +85,8 @@ const dateChangeInjection = fromCallback(({
if (!belongsToCurrentCwd()) return undefined;
const renderGeneration = profileData.renderGeneration ?? 0;
const current = currentDateDisclosure(clock);
const profileDate = dateFromProfile();
const seed = runtime.getLogicState<DateChangeActorContext>().seed;
const baseline = pickDisclosureBaseline<DateDisclosure>(
lastDisclosure,
profileDate,
seed,
);
const baseline = pickDisclosureBaseline<DateDisclosure>(lastDisclosure, seed);
if (baseline !== undefined && baseline.localDate !== current.localDate) {
return {
content: `The date has changed. Today's date is now ${current.localDate}. Rely on this reminder over any earlier date statement for the current date. DO NOT mention this to the user explicitly.`,
Expand All @@ -113,7 +98,7 @@ const dateChangeInjection = fromCallback(({
},
};
}
if (lastDisclosure !== undefined || profileDate !== undefined) return undefined;
if (lastDisclosure !== undefined) return undefined;
if (seed === undefined) {
runtime.send({
type: 'dateChange.disclose',
Expand Down
15 changes: 4 additions & 11 deletions packages/agent-core-v2/test/agent/profile/binding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { BuiltinAgentProfileLoaderService } from '#/app/agentProfileCatalog/buil
import { registerAgentProfile } from '#/app/agentProfileCatalog/contribution';
import type { ToolCall } from '#/kosong/contract/message';
import { IAgentProfileService, type ResolvedAgentProfile } from '#/agent/profile/profile';
import { IHostClock } from '#/os/interface/hostClock';
import type { HostFsChange } from '#/os/interface/hostFsWatch';
import { IAgentAgentsMdReminderService } from '#/agent/agentsMdReminder/agentsMdReminder';
import { IAgentToolPolicyService } from '#/agent/toolPolicy/toolPolicy';
Expand All @@ -26,6 +25,7 @@ import { IAgentToolRegistryService } from '#/agent/toolRegistry/toolRegistry';
import { SELECT_TOOLS_TOOL_NAME } from '#/agent/toolSelect/toolSelect';
import { IAtomicDocumentStore, type IAtomicDocumentStore as AtomicDocumentStore } from '#/persistence/interface/atomicDocumentStore';
import { ISessionAgentProfileCatalog } from '#/session/sessionAgentProfileCatalog/sessionAgentProfileCatalog';
import { ISessionContext } from '#/session/sessionContext/sessionContext';
import { ISessionInstructionsProvider } from '#/session/sessionInstructions/instructionsProvider';
import { ISessionSkillCatalog } from '#/features/skill/session/skillCatalog';
import { ISessionToolPolicy } from '#/session/sessionToolPolicy/sessionToolPolicy';
Expand Down Expand Up @@ -141,21 +141,14 @@ describe('AgentProfileService.bind', () => {
expect(svc.isRunnable()).toBe(true);
});

it('keeps the rendered prompt and disclosure free of clock-dependent content', async () => {
const hostClock: IHostClock = {
_serviceBrand: undefined,
now: () => new Date('2026-07-29T04:00:00.000Z'),
timeZone: () => 'Asia/Shanghai',
};
ctx = createTestAgent(appService(IHostClock, hostClock), hostEnvironmentServices(homeDir));
it('binds an environment disclosure snapshot with only the session cwd', async () => {
ctx = createTestAgent(hostEnvironmentServices(homeDir));
const svc = ctx.get(IAgentProfileService);

await svc.bind({ profile: DEFAULT_AGENT_PROFILE_NAME, model: MOCK_MODEL });

expect(svc.getSystemPrompt()).not.toContain('2026-07-29');
expect(svc.data().environmentDisclosure).toMatchObject({
date: { disclosed: false },
});
expect(svc.data().environmentDisclosure).toEqual({ cwd: ctx.get(ISessionContext).cwd });
});

it('persists the complete binding in one journal record', async () => {
Expand Down
16 changes: 2 additions & 14 deletions packages/agent-core-v2/test/agent/profile/profileOps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,13 +352,7 @@ describe('AgentProfileService (wire-backed config.update)', () => {
});

it('persists the rendered prompt and disclosure snapshot in one bind record', async () => {
const environment: EnvironmentDisclosureSnapshot = {
cwd: '/work',
date: {
disclosed: true,
value: { localDate: '2026-07-29', timeZone: 'Asia/Shanghai' },
},
};
const environment: EnvironmentDisclosureSnapshot = { cwd: '/work' };
svc.applyBindingSnapshot({
modelAlias: 'kimi-code',
profileName: 'agent',
Expand Down Expand Up @@ -397,13 +391,7 @@ describe('AgentProfileService (wire-backed config.update)', () => {
});

it('replays a legacy config.update record with an explicit renderGeneration verbatim', async () => {
const environment: EnvironmentDisclosureSnapshot = {
cwd: '/work',
date: {
disclosed: true,
value: { localDate: '2026-07-29', timeZone: 'Asia/Shanghai' },
},
};
const environment: EnvironmentDisclosureSnapshot = { cwd: '/work' };

const replay = buildHost('profile-replay-legacy-generation');
await restoreTestEventDispatcher(
Expand Down
Loading
Loading