@qduc/term2 0.32.0 → 0.32.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js.map +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +2 -2
- package/dist/app.js.map +1 -1
- package/dist/build-info.json +2 -2
- package/dist/components/InputBox.js +12 -3
- package/dist/components/InputBox.js.map +1 -1
- package/dist/components/layout/BackgroundTasksPanel.d.ts.map +1 -1
- package/dist/components/layout/BackgroundTasksPanel.js +6 -8
- package/dist/components/layout/BackgroundTasksPanel.js.map +1 -1
- package/dist/components/layout/BottomArea.d.ts +2 -0
- package/dist/components/layout/BottomArea.d.ts.map +1 -1
- package/dist/components/layout/BottomArea.js +37 -10
- package/dist/components/layout/BottomArea.js.map +1 -1
- package/dist/components/prompt/ApprovalPrompt.d.ts.map +1 -1
- package/dist/components/prompt/ApprovalPrompt.js +22 -1
- package/dist/components/prompt/ApprovalPrompt.js.map +1 -1
- package/dist/contracts/streamed-model-turn.d.ts +4 -0
- package/dist/contracts/streamed-model-turn.d.ts.map +1 -1
- package/dist/contracts/streamed-model-turn.js.map +1 -1
- package/dist/hooks/conversation-ui-reducer.d.ts +11 -0
- package/dist/hooks/conversation-ui-reducer.d.ts.map +1 -1
- package/dist/hooks/conversation-ui-reducer.js +11 -3
- package/dist/hooks/conversation-ui-reducer.js.map +1 -1
- package/dist/hooks/use-conversation.d.ts +1 -0
- package/dist/hooks/use-conversation.d.ts.map +1 -1
- package/dist/hooks/use-conversation.js +12 -2
- package/dist/hooks/use-conversation.js.map +1 -1
- package/dist/hooks/use-model-selection.d.ts.map +1 -1
- package/dist/hooks/use-model-selection.js +5 -7
- package/dist/hooks/use-model-selection.js.map +1 -1
- package/dist/hooks/use-standalone-model-picker.d.ts.map +1 -1
- package/dist/hooks/use-standalone-model-picker.js +3 -4
- package/dist/hooks/use-standalone-model-picker.js.map +1 -1
- package/dist/lib/agent-chat-service.js +2 -2
- package/dist/lib/agent-chat-service.js.map +1 -1
- package/dist/lib/agent-client.d.ts +2 -1
- package/dist/lib/agent-client.d.ts.map +1 -1
- package/dist/lib/agent-client.js +3 -3
- package/dist/lib/agent-client.js.map +1 -1
- package/dist/lib/agent-configuration.d.ts +5 -3
- package/dist/lib/agent-configuration.d.ts.map +1 -1
- package/dist/lib/agent-configuration.js +5 -4
- package/dist/lib/agent-configuration.js.map +1 -1
- package/dist/providers/ai-sdk-streamed-model.d.ts.map +1 -1
- package/dist/providers/ai-sdk-streamed-model.js +15 -3
- package/dist/providers/ai-sdk-streamed-model.js.map +1 -1
- package/dist/providers/codex.provider.d.ts +3 -2
- package/dist/providers/codex.provider.d.ts.map +1 -1
- package/dist/providers/codex.provider.js.map +1 -1
- package/dist/providers/registry.d.ts +2 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/retrying-model.d.ts +8 -4
- package/dist/providers/retrying-model.d.ts.map +1 -1
- package/dist/providers/retrying-model.js +1 -1
- package/dist/providers/retrying-model.js.map +1 -1
- package/dist/services/agent-runtime/application-run-loop.d.ts.map +1 -1
- package/dist/services/agent-runtime/application-run-loop.js +3 -0
- package/dist/services/agent-runtime/application-run-loop.js.map +1 -1
- package/dist/services/agent-runtime/tool-call-execution.d.ts.map +1 -1
- package/dist/services/agent-runtime/tool-call-execution.js +7 -1
- package/dist/services/agent-runtime/tool-call-execution.js.map +1 -1
- package/dist/services/agent-runtime/workflow/workflow-evaluator.d.ts +5 -0
- package/dist/services/agent-runtime/workflow/workflow-evaluator.d.ts.map +1 -1
- package/dist/services/agent-runtime/workflow/workflow-evaluator.js +6 -1
- package/dist/services/agent-runtime/workflow/workflow-evaluator.js.map +1 -1
- package/dist/services/conversation/conversation-orchestrator.d.ts.map +1 -1
- package/dist/services/conversation/conversation-orchestrator.js +33 -0
- package/dist/services/conversation/conversation-orchestrator.js.map +1 -1
- package/dist/services/conversation/conversation-orchestrator.types.d.ts +6 -0
- package/dist/services/conversation/conversation-orchestrator.types.d.ts.map +1 -1
- package/dist/services/conversation/conversation-service.d.ts +2 -1
- package/dist/services/conversation/conversation-service.d.ts.map +1 -1
- package/dist/services/conversation/conversation-service.js.map +1 -1
- package/dist/services/conversation-agent-client.d.ts +2 -1
- package/dist/services/conversation-agent-client.d.ts.map +1 -1
- package/dist/services/memory/memory-capabilities.d.ts +2 -2
- package/dist/services/memory/memory-capabilities.d.ts.map +1 -1
- package/dist/services/models/unified-model-catalog.d.ts.map +1 -1
- package/dist/services/models/unified-model-catalog.js +26 -1
- package/dist/services/models/unified-model-catalog.js.map +1 -1
- package/dist/services/retry/retry-error-classification.d.ts.map +1 -1
- package/dist/services/retry/retry-error-classification.js +3 -0
- package/dist/services/retry/retry-error-classification.js.map +1 -1
- package/dist/services/retry/retry-event-presenter.d.ts.map +1 -1
- package/dist/services/retry/retry-event-presenter.js +1 -0
- package/dist/services/retry/retry-event-presenter.js.map +1 -1
- package/dist/services/retry/upstream-retry-policy.d.ts.map +1 -1
- package/dist/services/retry/upstream-retry-policy.js +49 -3
- package/dist/services/retry/upstream-retry-policy.js.map +1 -1
- package/dist/services/session/session-runtime-controller.d.ts +2 -1
- package/dist/services/session/session-runtime-controller.d.ts.map +1 -1
- package/dist/services/session/session-runtime-controller.js.map +1 -1
- package/dist/services/session/session-stream-processor.d.ts.map +1 -1
- package/dist/services/session/session-stream-processor.js +11 -0
- package/dist/services/session/session-stream-processor.js.map +1 -1
- package/dist/services/session/session-tool-tracker.d.ts +17 -1
- package/dist/services/session/session-tool-tracker.d.ts.map +1 -1
- package/dist/services/session/session-tool-tracker.js +30 -1
- package/dist/services/session/session-tool-tracker.js.map +1 -1
- package/dist/services/subagents/tool-policy.d.ts +10 -10
- package/dist/services/subagents/tool-policy.d.ts.map +1 -1
- package/dist/services/subagents/tool-policy.js.map +1 -1
- package/dist/skins/cards/live-region.d.ts.map +1 -1
- package/dist/skins/cards/live-region.js +6 -3
- package/dist/skins/cards/live-region.js.map +1 -1
- package/dist/skins/classic/live-region.d.ts.map +1 -1
- package/dist/skins/classic/live-region.js +9 -2
- package/dist/skins/classic/live-region.js.map +1 -1
- package/dist/skins/ledger/live-region.d.ts.map +1 -1
- package/dist/skins/ledger/live-region.js +6 -3
- package/dist/skins/ledger/live-region.js.map +1 -1
- package/dist/skins/rail/live-region.d.ts.map +1 -1
- package/dist/skins/rail/live-region.js +8 -2
- package/dist/skins/rail/live-region.js.map +1 -1
- package/dist/skins/testing/scenes.d.ts.map +1 -1
- package/dist/skins/testing/scenes.js +17 -0
- package/dist/skins/testing/scenes.js.map +1 -1
- package/dist/skins/types.d.ts +8 -1
- package/dist/skins/types.d.ts.map +1 -1
- package/dist/skins/types.js.map +1 -1
- package/dist/skins/zen/live-region.d.ts.map +1 -1
- package/dist/skins/zen/live-region.js +7 -3
- package/dist/skins/zen/live-region.js.map +1 -1
- package/dist/test-helpers/vitest-cache-global-setup.d.ts +3 -0
- package/dist/test-helpers/vitest-cache-global-setup.d.ts.map +1 -0
- package/dist/test-helpers/vitest-cache-global-setup.js +12 -0
- package/dist/test-helpers/vitest-cache-global-setup.js.map +1 -0
- package/dist/test-helpers/vitest-cache-isolation.d.ts +5 -0
- package/dist/test-helpers/vitest-cache-isolation.d.ts.map +1 -1
- package/dist/test-helpers/vitest-cache-isolation.js +7 -2
- package/dist/test-helpers/vitest-cache-isolation.js.map +1 -1
- package/dist/tools/agent/activate-skill.d.ts +2 -2
- package/dist/tools/agent/activate-skill.d.ts.map +1 -1
- package/dist/tools/agent/activate-skill.js +1 -0
- package/dist/tools/agent/activate-skill.js.map +1 -1
- package/dist/tools/agent/ask-mentor.d.ts +1 -1
- package/dist/tools/agent/ask-mentor.d.ts.map +1 -1
- package/dist/tools/agent/ask-mentor.js.map +1 -1
- package/dist/tools/agent/ask-orchestrator.d.ts +2 -2
- package/dist/tools/agent/ask-orchestrator.d.ts.map +1 -1
- package/dist/tools/agent/ask-orchestrator.js +1 -0
- package/dist/tools/agent/ask-orchestrator.js.map +1 -1
- package/dist/tools/agent/ask-user.d.ts +2 -1
- package/dist/tools/agent/ask-user.d.ts.map +1 -1
- package/dist/tools/agent/ask-user.js.map +1 -1
- package/dist/tools/agent/configure-task-check-in.d.ts +2 -2
- package/dist/tools/agent/configure-task-check-in.d.ts.map +1 -1
- package/dist/tools/agent/goal-check.d.ts +2 -1
- package/dist/tools/agent/goal-check.d.ts.map +1 -1
- package/dist/tools/agent/propose-goal.d.ts +2 -2
- package/dist/tools/agent/propose-goal.d.ts.map +1 -1
- package/dist/tools/agent/propose-goal.js +1 -0
- package/dist/tools/agent/propose-goal.js.map +1 -1
- package/dist/tools/agent/run-explorer.d.ts +2 -2
- package/dist/tools/agent/run-explorer.d.ts.map +1 -1
- package/dist/tools/agent/run-explorer.js +1 -0
- package/dist/tools/agent/run-explorer.js.map +1 -1
- package/dist/tools/agent/run-subagent-async.d.ts +5 -5
- package/dist/tools/agent/run-subagent-async.d.ts.map +1 -1
- package/dist/tools/agent/run-subagent-async.js +4 -0
- package/dist/tools/agent/run-subagent-async.js.map +1 -1
- package/dist/tools/agent/run-subagent.d.ts +2 -2
- package/dist/tools/agent/run-subagent.d.ts.map +1 -1
- package/dist/tools/file/apply-patch.d.ts +2 -2
- package/dist/tools/file/apply-patch.d.ts.map +1 -1
- package/dist/tools/file/code-context.d.ts +3 -3
- package/dist/tools/file/code-context.d.ts.map +1 -1
- package/dist/tools/file/code-context.js +59 -0
- package/dist/tools/file/code-context.js.map +1 -1
- package/dist/tools/file/create-file.d.ts +2 -2
- package/dist/tools/file/create-file.d.ts.map +1 -1
- package/dist/tools/file/create-file.js +1 -0
- package/dist/tools/file/create-file.js.map +1 -1
- package/dist/tools/file/glob.d.ts +2 -2
- package/dist/tools/file/glob.d.ts.map +1 -1
- package/dist/tools/file/glob.js.map +1 -1
- package/dist/tools/file/grep.d.ts +2 -2
- package/dist/tools/file/grep.d.ts.map +1 -1
- package/dist/tools/file/grep.js +1 -0
- package/dist/tools/file/grep.js.map +1 -1
- package/dist/tools/file/read-file.d.ts +2 -2
- package/dist/tools/file/read-file.d.ts.map +1 -1
- package/dist/tools/file/read-file.js +27 -0
- package/dist/tools/file/read-file.js.map +1 -1
- package/dist/tools/file/search-replace.d.ts +2 -2
- package/dist/tools/file/search-replace.d.ts.map +1 -1
- package/dist/tools/file/search-replace.js +1 -0
- package/dist/tools/file/search-replace.js.map +1 -1
- package/dist/tools/memory/memory-tools.d.ts +2 -2
- package/dist/tools/memory/memory-tools.d.ts.map +1 -1
- package/dist/tools/memory/memory-tools.js +4 -0
- package/dist/tools/memory/memory-tools.js.map +1 -1
- package/dist/tools/run-agent-workflow.d.ts +1 -1
- package/dist/tools/run-agent-workflow.d.ts.map +1 -1
- package/dist/tools/session-browser/session-browser-tools.d.ts +2 -2
- package/dist/tools/session-browser/session-browser-tools.d.ts.map +1 -1
- package/dist/tools/session-browser/session-browser-tools.js +106 -4
- package/dist/tools/session-browser/session-browser-tools.js.map +1 -1
- package/dist/tools/session-rollover/session-rollover-tool.d.ts +1 -1
- package/dist/tools/session-rollover/session-rollover-tool.d.ts.map +1 -1
- package/dist/tools/system/run-code/run-code-runtime.d.ts.map +1 -1
- package/dist/tools/system/run-code/run-code-runtime.js +11 -5
- package/dist/tools/system/run-code/run-code-runtime.js.map +1 -1
- package/dist/tools/system/run-code/run-code.d.ts +1 -1
- package/dist/tools/system/run-code/run-code.d.ts.map +1 -1
- package/dist/tools/system/run-code/run-code.js.map +1 -1
- package/dist/tools/system/run-code/tools-header.d.ts +2 -1
- package/dist/tools/system/run-code/tools-header.d.ts.map +1 -1
- package/dist/tools/system/run-code/tools-header.js +9 -3
- package/dist/tools/system/run-code/tools-header.js.map +1 -1
- package/dist/tools/system/shell.d.ts +6 -6
- package/dist/tools/system/shell.d.ts.map +1 -1
- package/dist/tools/system/shell.js +4 -0
- package/dist/tools/system/shell.js.map +1 -1
- package/dist/tools/system/worktree.d.ts +3 -9
- package/dist/tools/system/worktree.d.ts.map +1 -1
- package/dist/tools/system/worktree.js.map +1 -1
- package/dist/tools/tool-names.d.ts +11 -0
- package/dist/tools/tool-names.d.ts.map +1 -1
- package/dist/tools/types.d.ts +38 -3
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js.map +1 -1
- package/dist/tools/web/web-fetch.d.ts +2 -2
- package/dist/tools/web/web-fetch.d.ts.map +1 -1
- package/dist/tools/web/web-fetch.js +1 -0
- package/dist/tools/web/web-fetch.js.map +1 -1
- package/dist/tools/web/web-search.d.ts +2 -2
- package/dist/tools/web/web-search.d.ts.map +1 -1
- package/dist/tools/web/web-search.js +1 -0
- package/dist/tools/web/web-search.js.map +1 -1
- package/dist/utils/conversation/conversation-event-handler.d.ts.map +1 -1
- package/dist/utils/conversation/conversation-event-handler.js +3 -1
- package/dist/utils/conversation/conversation-event-handler.js.map +1 -1
- package/dist/utils/streaming/extract-command-messages.d.ts +2 -0
- package/dist/utils/streaming/extract-command-messages.d.ts.map +1 -1
- package/dist/utils/streaming/extract-command-messages.js +4 -0
- package/dist/utils/streaming/extract-command-messages.js.map +1 -1
- package/dist/utils/streaming/streaming-session-factory.d.ts.map +1 -1
- package/dist/utils/streaming/streaming-session-factory.js +3 -0
- package/dist/utils/streaming/streaming-session-factory.js.map +1 -1
- package/package.json +4 -6
- package/dist/prompts/durable-goal-context.test.ts +0 -67
- package/dist/prompts/explorer-delegation-contract.test.ts +0 -44
- package/dist/prompts/memory-recall-notice.test.ts +0 -50
- package/dist/prompts/orchestrator-prompt.test.ts +0 -111
- package/dist/prompts/prefix-quality.test.ts +0 -115
- package/dist/prompts/prompt-constructor.test.ts +0 -423
- package/dist/prompts/prompt-profiles.test.ts +0 -22
- package/dist/prompts/reasoning-efficiency.test.ts +0 -12
- package/dist/prompts/search-via-shell.test.ts +0 -69
- package/dist/prompts/steering-notice.test.ts +0 -36
- package/dist/prompts/subagent-delegation.test.ts +0 -112
- package/dist/prompts/subagents/worker-prompt.test.ts +0 -54
- package/dist/prompts/unified-gpt-prompt.test.ts +0 -53
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import os from 'node:os';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { mkdtemp, rm } from 'node:fs/promises';
|
|
5
|
-
import { expect, it } from 'vitest';
|
|
6
|
-
import { getAgentDefinition } from '../agent.js';
|
|
7
|
-
import { createMockSettingsService } from '../services/settings/settings-service.mock.js';
|
|
8
|
-
import { PLAN_MODE_ENTER_NOTICE, profileEnterNotice } from '../services/mode-notices.js';
|
|
9
|
-
import { buildPromptSpec } from './prompt-constructor.js';
|
|
10
|
-
import { resolveProfile } from '../services/profiles/index.js';
|
|
11
|
-
|
|
12
|
-
const mockLogger = {
|
|
13
|
-
debug: () => {},
|
|
14
|
-
info: () => {},
|
|
15
|
-
warn: () => {},
|
|
16
|
-
error: () => {},
|
|
17
|
-
setCorrelationId: () => {},
|
|
18
|
-
clearCorrelationId: () => {},
|
|
19
|
-
getCorrelationId: () => undefined,
|
|
20
|
-
} as any;
|
|
21
|
-
|
|
22
|
-
const readPrompt = (file: string): string => fs.readFileSync(path.join(import.meta.dirname, file), 'utf8');
|
|
23
|
-
|
|
24
|
-
const PLAN_WORKFLOW_MARKER = 'Plan Mode Workflow';
|
|
25
|
-
const STUB_MODE_NOTICE_MARKER = 'Follow the notice; do not infer mode from this system prompt';
|
|
26
|
-
|
|
27
|
-
it('plan-mode stub is smaller than the full workflow and still names the live constraints', () => {
|
|
28
|
-
const stub = readPrompt('plan-mode-stub.md');
|
|
29
|
-
const full = readPrompt('plan-mode-info.md');
|
|
30
|
-
|
|
31
|
-
expect(stub.length).toBeLessThan(full.length / 2);
|
|
32
|
-
expect(stub).toContain('<system-notice>');
|
|
33
|
-
expect(stub).toContain('do not create or modify files');
|
|
34
|
-
expect(stub).toContain('write-capable subagents');
|
|
35
|
-
expect(stub).toContain(STUB_MODE_NOTICE_MARKER);
|
|
36
|
-
expect(stub).not.toContain('You are currently in **Standard Mode**');
|
|
37
|
-
expect(stub).not.toContain(PLAN_WORKFLOW_MARKER);
|
|
38
|
-
expect(stub).not.toContain('Acceptance criteria');
|
|
39
|
-
|
|
40
|
-
expect(full).toContain(PLAN_WORKFLOW_MARKER);
|
|
41
|
-
expect(full).toContain('Synthesize their findings yourself');
|
|
42
|
-
expect(full).toContain('Acceptance criteria');
|
|
43
|
-
expect(full).toContain('You are currently in **Plan Mode**.');
|
|
44
|
-
expect(full).not.toContain('You are currently in **Standard Mode**');
|
|
45
|
-
expect(PLAN_MODE_ENTER_NOTICE).toContain(PLAN_WORKFLOW_MARKER);
|
|
46
|
-
expect(PLAN_MODE_ENTER_NOTICE).toContain('You are currently in **Plan Mode**.');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('primes the enter notice when a session starts already in Plan Mode', () => {
|
|
50
|
-
const queued: string[] = [];
|
|
51
|
-
const inactiveNotice = profileEnterNotice('builtin:standard');
|
|
52
|
-
if (inactiveNotice) queued.push(inactiveNotice);
|
|
53
|
-
expect(queued).toEqual([]);
|
|
54
|
-
const activeNotice = profileEnterNotice('builtin:plan');
|
|
55
|
-
if (activeNotice) queued.push(activeNotice);
|
|
56
|
-
expect(queued).toEqual([PLAN_MODE_ENTER_NOTICE]);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('instruction prefix stays on the stub in both modes; the workflow rides on the enter notice', async () => {
|
|
60
|
-
const cwd = await mkdtemp(path.join(os.tmpdir(), 'term2-prefix-quality-'));
|
|
61
|
-
const executionContext = {
|
|
62
|
-
isRemote: () => false,
|
|
63
|
-
getCwd: () => cwd,
|
|
64
|
-
} as any;
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
const standard = getAgentDefinition({
|
|
68
|
-
settingsService: createMockSettingsService({
|
|
69
|
-
'agent.model': 'gpt-4o',
|
|
70
|
-
'app.planMode': false,
|
|
71
|
-
}),
|
|
72
|
-
loggingService: mockLogger,
|
|
73
|
-
executionContext,
|
|
74
|
-
});
|
|
75
|
-
const plan = getAgentDefinition({
|
|
76
|
-
settingsService: createMockSettingsService({
|
|
77
|
-
'agent.model': 'gpt-4o',
|
|
78
|
-
'app.planMode': true,
|
|
79
|
-
}),
|
|
80
|
-
loggingService: mockLogger,
|
|
81
|
-
executionContext,
|
|
82
|
-
});
|
|
83
|
-
const mentor = getAgentDefinition({
|
|
84
|
-
settingsService: createMockSettingsService({
|
|
85
|
-
'agent.model': 'gpt-4o',
|
|
86
|
-
'app.mentorMode': true,
|
|
87
|
-
}),
|
|
88
|
-
loggingService: mockLogger,
|
|
89
|
-
executionContext,
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
expect(standard.instructions).toContain(STUB_MODE_NOTICE_MARKER);
|
|
93
|
-
expect(plan.instructions).toContain(STUB_MODE_NOTICE_MARKER);
|
|
94
|
-
expect(standard.instructions).not.toContain(PLAN_WORKFLOW_MARKER);
|
|
95
|
-
expect(plan.instructions).not.toContain(PLAN_WORKFLOW_MARKER);
|
|
96
|
-
expect(plan.instructions).toBe(standard.instructions);
|
|
97
|
-
expect(mentor.instructions).toBe(standard.instructions);
|
|
98
|
-
expect(mentor.tools.map((tool) => tool.name)).toEqual(standard.tools.map((tool) => tool.name));
|
|
99
|
-
} finally {
|
|
100
|
-
await rm(cwd, { recursive: true, force: true });
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('product-controlled prefix does not attach the Plan Mode workflow file', () => {
|
|
105
|
-
const standard = buildPromptSpec({ model: 'gpt-4o', profile: resolveProfile('builtin:standard') });
|
|
106
|
-
const plan = buildPromptSpec({ model: 'gpt-4o', profile: resolveProfile('builtin:plan') });
|
|
107
|
-
|
|
108
|
-
expect(standard.fragmentFiles).toContain('plan-mode-stub.md');
|
|
109
|
-
expect(standard.fragmentFiles).not.toContain('plan-mode-info.md');
|
|
110
|
-
expect(plan.fragmentFiles).toEqual(standard.fragmentFiles);
|
|
111
|
-
|
|
112
|
-
const stubBytes = readPrompt('plan-mode-stub.md').length;
|
|
113
|
-
const fullBytes = readPrompt('plan-mode-info.md').length;
|
|
114
|
-
expect(stubBytes).toBeLessThan(fullBytes / 2);
|
|
115
|
-
});
|
|
@@ -1,423 +0,0 @@
|
|
|
1
|
-
import { it, expect } from 'vitest';
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { buildPromptSpec } from './prompt-constructor.js';
|
|
5
|
-
import { resolveProfile } from '../services/profiles/index.js';
|
|
6
|
-
import { getAgentDefinition } from '../agent.js';
|
|
7
|
-
import { createMockSettingsService } from '../services/settings/settings-service.mock.js';
|
|
8
|
-
import { ExecutionContext } from '../services/execution-context.js';
|
|
9
|
-
import { BackgroundShellRegistry } from '../services/shell/background-shell-registry.js';
|
|
10
|
-
import { BackgroundShellOutputStore } from '../services/shell/background-shell-output-store.js';
|
|
11
|
-
import { BackgroundShellWatches } from '../services/shell/background-shell-watches.js';
|
|
12
|
-
import { SessionBrowser } from '../services/conversation/session-browser.js';
|
|
13
|
-
import { RUN_CODE_PROHIBITED_TOOLS } from '../tools/system/run-code/run-code.js';
|
|
14
|
-
import { getBackgroundShellAddendum } from './background-shell.js';
|
|
15
|
-
import { getSubagentDelegationAddendum } from './subagent-delegation.js';
|
|
16
|
-
import { getDirectEditorToolsAddendum, getScriptPrimaryToolsAddendum } from './tool-surface-guidance.js';
|
|
17
|
-
|
|
18
|
-
it('guides run_code exact searches and syntax-sensitive data', () => {
|
|
19
|
-
const guidance = getScriptPrimaryToolsAddendum('editors');
|
|
20
|
-
|
|
21
|
-
expect(guidance).toContain('fixed_strings: true');
|
|
22
|
-
expect(guidance).toContain('pattern` is a regular expression');
|
|
23
|
-
expect(guidance).toContain('pass it through the `run_code` `inputs` parameter');
|
|
24
|
-
expect(guidance).toContain(
|
|
25
|
-
'- For multiline edit text or data containing quotes, backticks, or `${...}`, pass it through the `run_code` `inputs` parameter instead of embedding it in JavaScript source.',
|
|
26
|
-
);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('names only editors on the active run_code editing surface and identifies shell as direct-only', () => {
|
|
30
|
-
const patchSurface = buildPromptSpec({
|
|
31
|
-
model: 'gpt-5.6',
|
|
32
|
-
profile: profile('builtin:standard'),
|
|
33
|
-
runCodeEnabled: true,
|
|
34
|
-
editorSurface: 'patch',
|
|
35
|
-
}).inlineSections.join('\n');
|
|
36
|
-
const otherSurface = buildPromptSpec({
|
|
37
|
-
model: 'claude-3.7-sonnet',
|
|
38
|
-
profile: profile('builtin:standard'),
|
|
39
|
-
runCodeEnabled: true,
|
|
40
|
-
editorSurface: 'editors',
|
|
41
|
-
}).inlineSections.join('\n');
|
|
42
|
-
const noWriteSurface = buildPromptSpec({
|
|
43
|
-
model: 'claude-3.7-sonnet',
|
|
44
|
-
profile: profile('builtin:standard'),
|
|
45
|
-
runCodeEnabled: true,
|
|
46
|
-
editorSurface: 'none',
|
|
47
|
-
}).inlineSections.join('\n');
|
|
48
|
-
|
|
49
|
-
expect(patchSurface).toContain('`tools.apply_patch`');
|
|
50
|
-
expect(patchSurface).not.toContain('`tools.create_file`');
|
|
51
|
-
expect(patchSurface).not.toContain('`tools.search_replace`');
|
|
52
|
-
expect(patchSurface).toContain('create new files with a `*** Add File:` patch');
|
|
53
|
-
expect(otherSurface).toContain('`tools.create_file`');
|
|
54
|
-
expect(otherSurface).toContain('`tools.search_replace`');
|
|
55
|
-
expect(otherSurface).not.toContain('`tools.apply_patch`');
|
|
56
|
-
expect(noWriteSurface).not.toContain('`tools.apply_patch`');
|
|
57
|
-
expect(noWriteSurface).not.toContain('`tools.create_file`');
|
|
58
|
-
expect(noWriteSurface).not.toContain('`tools.search_replace`');
|
|
59
|
-
for (const surface of [patchSurface, otherSurface, noWriteSurface]) {
|
|
60
|
-
expect(surface).toContain('`tools.shell` does not exist inside `run_code`');
|
|
61
|
-
}
|
|
62
|
-
expect(patchSurface).toContain('Do not write files with');
|
|
63
|
-
expect(otherSurface).toContain('Do not write files with');
|
|
64
|
-
expect(patchSurface).toContain('heredocs, Python, or other shell tricks');
|
|
65
|
-
expect(otherSurface).toContain('heredocs, Python, or other shell tricks');
|
|
66
|
-
for (const surface of [patchSurface, otherSurface, noWriteSurface]) {
|
|
67
|
-
expect(surface).toContain('Do not use Python to read files when `tools.read_file` is available');
|
|
68
|
-
}
|
|
69
|
-
expect(noWriteSurface).not.toContain('Do not write files with');
|
|
70
|
-
expect(noWriteSurface).toContain('## File, search, and web tools');
|
|
71
|
-
expect(noWriteSurface).toContain('tools.grep({ pattern, fixed_strings: true })');
|
|
72
|
-
expect(noWriteSurface).not.toContain('\\n\\n');
|
|
73
|
-
expect(patchSurface).toContain('`shell` is a direct tool');
|
|
74
|
-
expect(patchSurface).toContain('File, search, web, and edit tools are not on your direct tool list.');
|
|
75
|
-
expect(otherSurface).toContain('File, search, web, and edit tools are not on your direct tool list.');
|
|
76
|
-
expect(noWriteSurface).toContain('File, search, and web tools are not on your direct tool list.');
|
|
77
|
-
expect(patchSurface).toContain('`tools.shell` does not exist inside `run_code`');
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
const fullCapabilityLogging = {
|
|
81
|
-
debug: () => {},
|
|
82
|
-
info: () => {},
|
|
83
|
-
warn: () => {},
|
|
84
|
-
error: () => {},
|
|
85
|
-
security: () => {},
|
|
86
|
-
setCorrelationId: () => {},
|
|
87
|
-
clearCorrelationId: () => {},
|
|
88
|
-
getCorrelationId: () => undefined,
|
|
89
|
-
} as any;
|
|
90
|
-
|
|
91
|
-
function fullCapabilityTools() {
|
|
92
|
-
const settingsService = createMockSettingsService({
|
|
93
|
-
'agent.model': 'gpt-4o',
|
|
94
|
-
'agent.smartModel': 'gpt-4o',
|
|
95
|
-
'app.searchViaShell': 'off',
|
|
96
|
-
enable_agent_workflow: true,
|
|
97
|
-
'sandbox.enabled': true,
|
|
98
|
-
});
|
|
99
|
-
const executionContext = new ExecutionContext();
|
|
100
|
-
const backgroundShellRegistry = new BackgroundShellRegistry();
|
|
101
|
-
const store = new BackgroundShellOutputStore();
|
|
102
|
-
const backgroundShellOutput = {
|
|
103
|
-
store,
|
|
104
|
-
watches: new BackgroundShellWatches({ store, scheduler: { schedule: () => 0, cancel: () => {} } }),
|
|
105
|
-
};
|
|
106
|
-
const skillsService = {
|
|
107
|
-
getAvailableSkillsForModel: () => [{ name: 'measurement', location: '/tmp/measurement', body: '' }],
|
|
108
|
-
getSkillCatalog: () => '',
|
|
109
|
-
} as any;
|
|
110
|
-
const sessionBrowser = new SessionBrowser(() => ({ projectPath: process.cwd() }));
|
|
111
|
-
const status = {
|
|
112
|
-
runId: 'measurement',
|
|
113
|
-
role: 'worker',
|
|
114
|
-
status: 'completed',
|
|
115
|
-
task: 'measurement',
|
|
116
|
-
taskPreview: 'measurement',
|
|
117
|
-
startedAt: 0,
|
|
118
|
-
elapsedMs: 0,
|
|
119
|
-
toolCounts: {},
|
|
120
|
-
} as any;
|
|
121
|
-
return getAgentDefinition(
|
|
122
|
-
{
|
|
123
|
-
settingsService,
|
|
124
|
-
loggingService: fullCapabilityLogging,
|
|
125
|
-
executionContext,
|
|
126
|
-
askMentor: async () => 'mentor',
|
|
127
|
-
runSubagent: async () => ({ finalText: 'subagent' }),
|
|
128
|
-
runSubagentAsync: async () => ({ runId: 'measurement', role: 'worker', status: 'running', task: 'measurement' }),
|
|
129
|
-
getSubagentResult: async () => ({
|
|
130
|
-
agentId: 'measurement',
|
|
131
|
-
role: 'worker',
|
|
132
|
-
status: 'completed',
|
|
133
|
-
finalText: 'subagent',
|
|
134
|
-
filesChanged: [],
|
|
135
|
-
toolsUsed: [],
|
|
136
|
-
}),
|
|
137
|
-
getSubagentStatus: () => status,
|
|
138
|
-
sendSubagentMessage: () => ({ ok: true, runId: 'measurement', status: 'running', delivery: 'queued' }),
|
|
139
|
-
cancelSubagentRun: () => ({ ok: true, runId: 'measurement', status: 'cancelling' }),
|
|
140
|
-
getAskUserAnswer: () => 'answer',
|
|
141
|
-
skillsService,
|
|
142
|
-
agentRuntime: { agent: () => ({} as any) },
|
|
143
|
-
backgroundShellRegistry: backgroundShellRegistry as any,
|
|
144
|
-
backgroundShellOutput,
|
|
145
|
-
sessionBrowser,
|
|
146
|
-
requestSessionRollover: () => ({} as any),
|
|
147
|
-
configureTaskCheckIn: () => ({} as any),
|
|
148
|
-
setTaskCheckInPolicy: () => {},
|
|
149
|
-
},
|
|
150
|
-
'gpt-4o',
|
|
151
|
-
).tools;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const profile = (id: string) => resolveProfile(id);
|
|
155
|
-
|
|
156
|
-
it('buildPromptSpec selects the profile identity and model-family base prompt', () => {
|
|
157
|
-
expect(buildPromptSpec({ model: 'gpt-5.5', profile: profile('builtin:lite') }).basePromptContent).toBeTruthy();
|
|
158
|
-
expect(buildPromptSpec({ model: 'claude-3-sonnet', profile: profile('builtin:standard') }).basePromptFile).toBe(
|
|
159
|
-
'anthropic.md',
|
|
160
|
-
);
|
|
161
|
-
expect(buildPromptSpec({ model: 'gpt-4o', profile: profile('builtin:standard') }).basePromptFile).toBe(
|
|
162
|
-
'simple_v4.md',
|
|
163
|
-
);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('buildPromptSpec keeps all non-lite built-in profiles prompt-spec equivalent', () => {
|
|
167
|
-
const specs = ['standard', 'plan', 'mentor', 'orchestrator'].map((id) =>
|
|
168
|
-
buildPromptSpec({ model: 'gpt-5.6', profile: profile(`builtin:${id}`) }),
|
|
169
|
-
);
|
|
170
|
-
expect(specs[1]).toEqual(specs[0]);
|
|
171
|
-
expect(specs[2]).toEqual(specs[0]);
|
|
172
|
-
expect(specs[3]).toEqual(specs[0]);
|
|
173
|
-
expect(buildPromptSpec({ model: 'gpt-5.6', profile: profile('builtin:lite') })).not.toEqual(specs[0]);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('buildPromptSpec composes file fragments in stable order', () => {
|
|
177
|
-
const spec = buildPromptSpec({
|
|
178
|
-
model: 'gpt-5.4-mini',
|
|
179
|
-
profile: profile('builtin:standard'),
|
|
180
|
-
searchViaShell: true,
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
expect(spec.fragmentFiles).toEqual([
|
|
184
|
-
'approval-model.md',
|
|
185
|
-
'worktree-hygiene.md',
|
|
186
|
-
'plan-mode-stub.md',
|
|
187
|
-
'pair-mode-stub.md',
|
|
188
|
-
'mentor-mode-stub.md',
|
|
189
|
-
'orchestrator-mode-stub.md',
|
|
190
|
-
]);
|
|
191
|
-
|
|
192
|
-
expect(spec.inlineSections).toContainEqual(expect.stringContaining('## Shell Sandbox'));
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
it('does not teach loaded run_code instruction surfaces to call script-only tools directly', () => {
|
|
196
|
-
const tools = fullCapabilityTools();
|
|
197
|
-
const scriptOnly = tools.filter((tool) => !RUN_CODE_PROHIBITED_TOOLS.has(tool.name)).map((tool) => tool.name);
|
|
198
|
-
const surfaces = ['lite.md', 'session-browser.md', 'orchestrator.md', 'gpt.md'].map((file) =>
|
|
199
|
-
readFileSync(join(import.meta.dirname, file), 'utf8'),
|
|
200
|
-
);
|
|
201
|
-
surfaces.push(
|
|
202
|
-
getScriptPrimaryToolsAddendum('editors'),
|
|
203
|
-
getBackgroundShellAddendum(),
|
|
204
|
-
getSubagentDelegationAddendum({ backgroundEnabled: true, controlsEnabled: true, foregroundEnabled: false }),
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
const directReferences = scriptOnly.flatMap((name) => {
|
|
208
|
-
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
209
|
-
// This preceding-dot exclusion is load-bearing: tools.<name> is the valid
|
|
210
|
-
// script reference form and must not count as a bare direct-tool reference.
|
|
211
|
-
const pattern = new RegExp(`(?<![A-Za-z0-9_.])${escaped}(?![A-Za-z0-9_])`);
|
|
212
|
-
return surfaces.some((surface) => pattern.test(surface)) ? [name] : [];
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
expect(directReferences).toEqual([]);
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
it('selects script-primary vs direct-editor guidance from runCodeEnabled', () => {
|
|
219
|
-
const enabled = buildPromptSpec({
|
|
220
|
-
model: 'gpt-5.6',
|
|
221
|
-
profile: profile('builtin:standard'),
|
|
222
|
-
runCodeEnabled: true,
|
|
223
|
-
editorSurface: 'patch',
|
|
224
|
-
});
|
|
225
|
-
const disabled = buildPromptSpec({
|
|
226
|
-
model: 'gpt-5.6',
|
|
227
|
-
profile: profile('builtin:standard'),
|
|
228
|
-
runCodeEnabled: false,
|
|
229
|
-
});
|
|
230
|
-
expect(enabled.inlineSections.join('\n')).toContain(getScriptPrimaryToolsAddendum('patch'));
|
|
231
|
-
expect(enabled.inlineSections.join('\n')).not.toContain(getDirectEditorToolsAddendum());
|
|
232
|
-
expect(disabled.inlineSections.join('\n')).toContain(getDirectEditorToolsAddendum());
|
|
233
|
-
expect(disabled.inlineSections.join('\n')).not.toContain(getScriptPrimaryToolsAddendum('patch'));
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
it('buildPromptSpec ships the approval mechanism to every non-lite profile', () => {
|
|
237
|
-
for (const model of ['gpt-5.6-sol', 'gpt-5.5', 'gpt-5.4', 'gpt-4o', 'claude-opus-4', 'kimi-k2']) {
|
|
238
|
-
const spec = buildPromptSpec({ model, profile: profile('builtin:standard') });
|
|
239
|
-
expect(spec.fragmentFiles).toContain('approval-model.md');
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const orchestrator = buildPromptSpec({ model: 'gpt-5.6-sol', profile: profile('builtin:orchestrator') });
|
|
243
|
-
expect(orchestrator.fragmentFiles).toContain('approval-model.md');
|
|
244
|
-
|
|
245
|
-
const lite = buildPromptSpec({ model: 'gpt-5.6-sol', profile: profile('builtin:lite') });
|
|
246
|
-
expect(lite.fragmentFiles).not.toContain('approval-model.md');
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
it('buildPromptSpec attaches the Plan Mode stub in standard and plan mode so the instruction prefix stays cache-stable', () => {
|
|
250
|
-
const standard = buildPromptSpec({ model: 'gpt-4o', profile: profile('builtin:standard') });
|
|
251
|
-
expect(standard.fragmentFiles.includes('plan-mode-stub.md')).toBe(true);
|
|
252
|
-
expect(standard.fragmentFiles.includes('plan-mode-info.md')).toBe(false);
|
|
253
|
-
|
|
254
|
-
const plan = buildPromptSpec({ model: 'gpt-4o', profile: profile('builtin:plan') });
|
|
255
|
-
expect(plan.fragmentFiles.includes('plan-mode-stub.md')).toBe(true);
|
|
256
|
-
expect(plan.fragmentFiles.includes('plan-mode-info.md')).toBe(false);
|
|
257
|
-
expect(plan.fragmentFiles).toEqual(standard.fragmentFiles);
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
it('buildPromptSpec keeps all non-lite mode stubs stable while lite stays minimal', () => {
|
|
261
|
-
const lite = buildPromptSpec({ model: 'gpt-5.5', profile: profile('builtin:lite') });
|
|
262
|
-
expect(lite.fragmentFiles.includes('plan-mode-info.md')).toBe(false);
|
|
263
|
-
expect(lite.fragmentFiles.includes('plan-mode-stub.md')).toBe(false);
|
|
264
|
-
expect(lite.fragmentFiles.includes('mentor-mode-stub.md')).toBe(false);
|
|
265
|
-
expect(lite.fragmentFiles.includes('orchestrator-mode-stub.md')).toBe(false);
|
|
266
|
-
|
|
267
|
-
const orchestrator = buildPromptSpec({ model: 'gpt-5.5', profile: profile('builtin:orchestrator') });
|
|
268
|
-
expect(orchestrator.fragmentFiles.includes('plan-mode-info.md')).toBe(false);
|
|
269
|
-
expect(orchestrator.fragmentFiles.includes('plan-mode-stub.md')).toBe(true);
|
|
270
|
-
expect(orchestrator.fragmentFiles.includes('mentor-mode-stub.md')).toBe(true);
|
|
271
|
-
expect(orchestrator.fragmentFiles.includes('orchestrator-mode-stub.md')).toBe(true);
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
it('buildPromptSpec keeps the non-lite instruction prefix identical across modes', () => {
|
|
275
|
-
const standard = buildPromptSpec({ model: 'gpt-4o', profile: profile('builtin:standard') });
|
|
276
|
-
const plan = buildPromptSpec({ model: 'gpt-4o', profile: profile('builtin:plan') });
|
|
277
|
-
const mentor = buildPromptSpec({ model: 'gpt-4o', profile: profile('builtin:mentor') });
|
|
278
|
-
const orchestrator = buildPromptSpec({ model: 'gpt-4o', profile: profile('builtin:orchestrator') });
|
|
279
|
-
|
|
280
|
-
expect(plan).toEqual(standard);
|
|
281
|
-
expect(mentor).toEqual(standard);
|
|
282
|
-
expect(orchestrator).toEqual(standard);
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
it('buildPromptSpec includes subagent delegation for orchestrator mode', () => {
|
|
286
|
-
const orchestrator = buildPromptSpec({
|
|
287
|
-
model: 'gpt-5.5',
|
|
288
|
-
profile: profile('builtin:orchestrator'),
|
|
289
|
-
runSubagentEnabled: true,
|
|
290
|
-
codeContextEnabled: true,
|
|
291
|
-
searchViaShell: false,
|
|
292
|
-
});
|
|
293
|
-
expect(orchestrator.inlineSections.some((s) => s.includes('Delegating to subagents'))).toBe(true);
|
|
294
|
-
expect(orchestrator.inlineSections.some((s) => s.includes('Delegate when it provides meaningful leverage'))).toBe(
|
|
295
|
-
true,
|
|
296
|
-
);
|
|
297
|
-
expect(orchestrator.inlineSections.some((s) => s.includes('Delegate workspace inspection'))).toBe(false);
|
|
298
|
-
expect(orchestrator.inlineSections.some((s) => s.includes('Code Context'))).toBe(false);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('buildPromptSpec uses lite base and skips worktree-hygiene fragment in lite mode', () => {
|
|
302
|
-
const lite = buildPromptSpec({
|
|
303
|
-
model: 'gpt-5.5',
|
|
304
|
-
profile: profile('builtin:lite'),
|
|
305
|
-
codeContextEnabled: true,
|
|
306
|
-
searchViaShell: false,
|
|
307
|
-
});
|
|
308
|
-
expect(lite.basePromptFile).toBeUndefined();
|
|
309
|
-
expect(lite.basePromptContent).toBeTruthy();
|
|
310
|
-
expect(lite.fragmentFiles.includes('worktree-hygiene.md')).toBe(false);
|
|
311
|
-
// Shell sandbox plus tool-surface routing are added inline in lite mode.
|
|
312
|
-
expect(lite.inlineSections.length).toBe(2);
|
|
313
|
-
expect(lite.inlineSections[0]).toContain('## Shell Sandbox');
|
|
314
|
-
expect(lite.inlineSections[1]).toContain('## File, search, and edit tools');
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
it('buildPromptSpec excludes shell-sandbox when sandbox is disabled', () => {
|
|
318
|
-
const spec = buildPromptSpec({
|
|
319
|
-
model: 'gpt-4o',
|
|
320
|
-
profile: profile('builtin:standard'),
|
|
321
|
-
sandboxEnabled: false,
|
|
322
|
-
});
|
|
323
|
-
expect(spec.inlineSections.some((s) => s.includes('## Shell Sandbox'))).toBe(false);
|
|
324
|
-
expect(spec.fragmentFiles.includes('worktree-hygiene.md')).toBe(true);
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
it('buildPromptSpec tells the model to wait for background shell completion instead of polling', () => {
|
|
328
|
-
const spec = buildPromptSpec({
|
|
329
|
-
model: 'gpt-4o',
|
|
330
|
-
profile: profile('builtin:standard'),
|
|
331
|
-
backgroundShellEnabled: true,
|
|
332
|
-
});
|
|
333
|
-
const guidance = spec.inlineSections.join('\n');
|
|
334
|
-
|
|
335
|
-
expect(guidance).toContain('Background shell jobs');
|
|
336
|
-
expect(guidance).toContain('`background: true`');
|
|
337
|
-
expect(guidance).toContain('do NOT call `tools.get_shell_job(...)` as a polling loop');
|
|
338
|
-
expect(guidance.toLowerCase()).toContain('end the current turn and wait for the automatic completion notification');
|
|
339
|
-
expect(guidance.toLowerCase()).toContain('do not run `sleep` merely to wait');
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
it('includes one memory guidance section and gates the pinned context by regular memory mode', () => {
|
|
343
|
-
const args = {
|
|
344
|
-
model: 'gpt-4o',
|
|
345
|
-
profile: profile('builtin:standard'),
|
|
346
|
-
memoryGuidance: 'Memory guidance',
|
|
347
|
-
memoryContext: 'Global-only index',
|
|
348
|
-
};
|
|
349
|
-
const enabled = buildPromptSpec({ ...args, memoryEnabled: true });
|
|
350
|
-
expect(enabled.inlineSections.filter((section) => section === 'Memory guidance')).toHaveLength(1);
|
|
351
|
-
expect(enabled.inlineSections).toContain('Global-only index');
|
|
352
|
-
expect(buildPromptSpec({ ...args, memoryEnabled: false }).inlineSections).not.toContain('Global-only index');
|
|
353
|
-
expect(
|
|
354
|
-
buildPromptSpec({ ...args, profile: profile('builtin:lite'), memoryEnabled: true }).inlineSections,
|
|
355
|
-
).not.toContain('Global-only index');
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
it('buildPromptSpec includes unified background delegation guidance when background execution is enabled', () => {
|
|
359
|
-
const spec = buildPromptSpec({
|
|
360
|
-
model: 'gpt-4o',
|
|
361
|
-
profile: profile('builtin:standard'),
|
|
362
|
-
runSubagentEnabled: true,
|
|
363
|
-
runSubagentAsyncEnabled: true,
|
|
364
|
-
});
|
|
365
|
-
expect(spec.inlineSections.some((s) => s.includes('execution: "background"'))).toBe(true);
|
|
366
|
-
expect(spec.inlineSections.some((s) => s.includes('run_subagent_async'))).toBe(false);
|
|
367
|
-
expect(spec.inlineSections.some((s) => s.includes('get_subagent_result'))).toBe(true);
|
|
368
|
-
expect(spec.inlineSections.some((s) => s.includes('explorer'))).toBe(true);
|
|
369
|
-
expect(spec.inlineSections.some((s) => s.includes('worker'))).toBe(true);
|
|
370
|
-
expect(spec.inlineSections.some((s) => s.includes('mentor'))).toBe(true);
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
it('buildPromptSpec tells orchestrators to trust successful delegation and wait without duplicating it', () => {
|
|
374
|
-
const spec = buildPromptSpec({
|
|
375
|
-
model: 'gpt-4o',
|
|
376
|
-
profile: profile('builtin:orchestrator'),
|
|
377
|
-
runSubagentEnabled: true,
|
|
378
|
-
runSubagentAsyncEnabled: true,
|
|
379
|
-
});
|
|
380
|
-
const guidance = spec.inlineSections.join('\n');
|
|
381
|
-
|
|
382
|
-
expect(guidance).toContain('`execution: "background"`');
|
|
383
|
-
expect(guidance).toContain('A returned handle with `status: "running"` means delegation succeeded');
|
|
384
|
-
expect(guidance).toContain('Do not duplicate or independently perform the delegated unit');
|
|
385
|
-
expect(guidance.toLowerCase()).toContain('end the current turn and wait for the completion notification');
|
|
386
|
-
expect(guidance).toContain('inlines the full result so you can continue directly');
|
|
387
|
-
expect(guidance).toContain('do NOT call `tools.get_subagent_result(...)` immediately');
|
|
388
|
-
expect(guidance).toContain('Active runs are refused rather than awaited');
|
|
389
|
-
expect(guidance).not.toContain('Use `run_subagent` only');
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
it('buildPromptSpec excludes async subagent guidance in lite mode', () => {
|
|
393
|
-
const spec = buildPromptSpec({
|
|
394
|
-
model: 'gpt-4o',
|
|
395
|
-
profile: profile('builtin:lite'),
|
|
396
|
-
runSubagentAsyncEnabled: true,
|
|
397
|
-
});
|
|
398
|
-
expect(spec.inlineSections.some((s) => s.includes('Asynchronous subagents'))).toBe(false);
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
it('buildPromptSpec excludes async subagent guidance when disabled', () => {
|
|
402
|
-
const spec = buildPromptSpec({
|
|
403
|
-
model: 'gpt-4o',
|
|
404
|
-
profile: profile('builtin:standard'),
|
|
405
|
-
runSubagentAsyncEnabled: false,
|
|
406
|
-
});
|
|
407
|
-
expect(spec.inlineSections.some((s) => s.includes('Asynchronous subagents'))).toBe(false);
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
it('background shell addendum teaches explicit finite timeouts for long-lived work', () => {
|
|
411
|
-
const spec = buildPromptSpec({
|
|
412
|
-
model: 'gpt-4o',
|
|
413
|
-
profile: profile('builtin:standard'),
|
|
414
|
-
backgroundShellEnabled: true,
|
|
415
|
-
});
|
|
416
|
-
const guidance = spec.inlineSections.join('\n');
|
|
417
|
-
|
|
418
|
-
expect(guidance).toContain('must pass an explicit finite `timeout_ms`');
|
|
419
|
-
expect(guidance).toContain('two hours for a watcher');
|
|
420
|
-
expect(guidance).toContain('15 minutes for a full-suite gate');
|
|
421
|
-
expect(guidance).toContain('never detach a job with nohup to escape the registry');
|
|
422
|
-
expect(guidance).toContain('Attach `monitor` in the same launch call');
|
|
423
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { it, expect } from 'vitest';
|
|
4
|
-
import { PROMPT_PROFILES, selectPromptProfile } from './prompt-profiles.js';
|
|
5
|
-
|
|
6
|
-
const PROMPTS_DIR = import.meta.dirname;
|
|
7
|
-
|
|
8
|
-
it('every prompt profile points at base and fragment files that exist on disk', () => {
|
|
9
|
-
const missing = PROMPT_PROFILES.flatMap((profile) =>
|
|
10
|
-
[profile.basePromptFile, ...(profile.fragmentFiles ?? [])]
|
|
11
|
-
.filter((file) => !fs.existsSync(path.join(PROMPTS_DIR, file)))
|
|
12
|
-
.map((file) => `${profile.id} -> ${file}`),
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
expect(missing).toEqual([]);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('selectPromptProfile resolves a profile for any model string', () => {
|
|
19
|
-
for (const model of ['gpt-5.6', 'gpt-5.5', 'claude-opus-5', 'kimi-k2.5', 'some-unknown-model', '']) {
|
|
20
|
-
expect(selectPromptProfile({ model, liteMode: false }).basePromptFile).toBeTruthy();
|
|
21
|
-
}
|
|
22
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { it, expect } from 'vitest';
|
|
2
|
-
import { getReasoningEfficiencyAddendum } from './reasoning-efficiency.js';
|
|
3
|
-
|
|
4
|
-
it('getReasoningEfficiencyAddendum returns a non-empty string with guidance keywords', () => {
|
|
5
|
-
const addendum = getReasoningEfficiencyAddendum();
|
|
6
|
-
|
|
7
|
-
expect(typeof addendum).toBe('string');
|
|
8
|
-
expect(addendum.length > 0).toBe(true);
|
|
9
|
-
expect(addendum.includes('### Reasoning Efficiency Guidelines')).toBe(true);
|
|
10
|
-
expect(addendum.includes('Treat confirmed context as settled')).toBe(true);
|
|
11
|
-
expect(addendum.includes('End when done')).toBe(true);
|
|
12
|
-
});
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { it, expect } from 'vitest';
|
|
2
|
-
import { getSearchViaShellAddendum } from './search-via-shell.js';
|
|
3
|
-
|
|
4
|
-
function includesWord(text: string, word: string): boolean {
|
|
5
|
-
return new RegExp(`\\b${word}\\b`, 'i').test(text);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
it('getSearchViaShellAddendum recommends rg and fd when both available', () => {
|
|
9
|
-
const result = getSearchViaShellAddendum({
|
|
10
|
-
checkBinary: () => true,
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
expect(includesWord(result, 'rg')).toBe(true);
|
|
14
|
-
expect(includesWord(result, 'fd')).toBe(true);
|
|
15
|
-
expect(includesWord(result, 'grep')).toBe(false);
|
|
16
|
-
expect(includesWord(result, 'find')).toBe(false);
|
|
17
|
-
expect(result.toLowerCase().includes('hygiene')).toBe(true);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('getSearchViaShellAddendum falls back to grep when rg is missing', () => {
|
|
21
|
-
const result = getSearchViaShellAddendum({
|
|
22
|
-
checkBinary: (cmd) => cmd === 'fd',
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
expect(includesWord(result, 'rg')).toBe(false);
|
|
26
|
-
expect(includesWord(result, 'grep')).toBe(true);
|
|
27
|
-
expect(includesWord(result, 'fd')).toBe(true);
|
|
28
|
-
expect(includesWord(result, 'find')).toBe(false);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('getSearchViaShellAddendum falls back to find when fd is missing', () => {
|
|
32
|
-
const result = getSearchViaShellAddendum({
|
|
33
|
-
checkBinary: (cmd) => cmd === 'rg',
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
expect(includesWord(result, 'rg')).toBe(true);
|
|
37
|
-
expect(includesWord(result, 'fd')).toBe(false);
|
|
38
|
-
expect(includesWord(result, 'find')).toBe(true);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('getSearchViaShellAddendum falls back to grep and find when both missing', () => {
|
|
42
|
-
const result = getSearchViaShellAddendum({
|
|
43
|
-
checkBinary: () => false,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
expect(includesWord(result, 'rg')).toBe(false);
|
|
47
|
-
expect(includesWord(result, 'grep')).toBe(true);
|
|
48
|
-
expect(includesWord(result, 'fd')).toBe(false);
|
|
49
|
-
expect(includesWord(result, 'find')).toBe(true);
|
|
50
|
-
expect(result.toLowerCase().includes('hygiene')).toBe(true);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('getSearchViaShellAddendum warns that pathless rg reads stdin', () => {
|
|
54
|
-
const result = getSearchViaShellAddendum({
|
|
55
|
-
checkBinary: () => true,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
expect(result.toLowerCase()).toContain('explicit path');
|
|
59
|
-
expect(result.toLowerCase()).toContain('stdin');
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('getSearchViaShellAddendum warns about find -regex alternation ordering', () => {
|
|
63
|
-
const result = getSearchViaShellAddendum({
|
|
64
|
-
checkBinary: () => false,
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
expect(result).toContain('-regex');
|
|
68
|
-
expect(result.toLowerCase()).toContain('longest alternative first');
|
|
69
|
-
});
|