feat(FN-4080): complete Step 1 — add thinking persistence resolver
Fusion-Task-Id: FN-4080 Fusion-Task-Lineage: 086863ba-7100-41ab-9cfc-197301fbcab0
This commit is contained in:
@@ -0,0 +1,44 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { resolvePersistAgentThinkingLog } from "../types.js";
|
||||||
|
|
||||||
|
describe("resolvePersistAgentThinkingLog", () => {
|
||||||
|
it("returns false for both kinds when granular and legacy are unset", () => {
|
||||||
|
expect(resolvePersistAgentThinkingLog({}, { ephemeral: false })).toBe(false);
|
||||||
|
expect(resolvePersistAgentThinkingLog({}, { ephemeral: true })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses granular permanent setting when defined", () => {
|
||||||
|
expect(
|
||||||
|
resolvePersistAgentThinkingLog(
|
||||||
|
{ persistAgentThinkingLogPermanent: true, persistAgentThinkingLogEphemeral: undefined },
|
||||||
|
{ ephemeral: false },
|
||||||
|
),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
resolvePersistAgentThinkingLog(
|
||||||
|
{ persistAgentThinkingLogPermanent: true, persistAgentThinkingLogEphemeral: undefined },
|
||||||
|
{ ephemeral: true },
|
||||||
|
),
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("falls back to legacy setting when granular fields are undefined", () => {
|
||||||
|
expect(resolvePersistAgentThinkingLog({ persistAgentThinkingLog: true }, { ephemeral: false })).toBe(true);
|
||||||
|
expect(resolvePersistAgentThinkingLog({ persistAgentThinkingLog: true }, { ephemeral: true })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("prioritizes granular setting over legacy fallback", () => {
|
||||||
|
expect(
|
||||||
|
resolvePersistAgentThinkingLog(
|
||||||
|
{ persistAgentThinkingLogPermanent: false, persistAgentThinkingLog: true },
|
||||||
|
{ ephemeral: false },
|
||||||
|
),
|
||||||
|
).toBe(false);
|
||||||
|
expect(
|
||||||
|
resolvePersistAgentThinkingLog(
|
||||||
|
{ persistAgentThinkingLogEphemeral: false, persistAgentThinkingLog: true },
|
||||||
|
{ ephemeral: true },
|
||||||
|
),
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -62,11 +62,19 @@ describe("settings key parity", () => {
|
|||||||
expect(isGlobalSettingsKey("persistAgentThinkingLog")).toBe(true);
|
expect(isGlobalSettingsKey("persistAgentThinkingLog")).toBe(true);
|
||||||
expect(isProjectSettingsKey("persistAgentThinkingLog")).toBe(false);
|
expect(isProjectSettingsKey("persistAgentThinkingLog")).toBe(false);
|
||||||
expect(isGlobalOnlySettingsKey("persistAgentThinkingLog")).toBe(true);
|
expect(isGlobalOnlySettingsKey("persistAgentThinkingLog")).toBe(true);
|
||||||
|
expect(isGlobalSettingsKey("persistAgentThinkingLogPermanent")).toBe(true);
|
||||||
|
expect(isProjectSettingsKey("persistAgentThinkingLogPermanent")).toBe(false);
|
||||||
|
expect(isGlobalOnlySettingsKey("persistAgentThinkingLogPermanent")).toBe(true);
|
||||||
|
expect(isGlobalSettingsKey("persistAgentThinkingLogEphemeral")).toBe(true);
|
||||||
|
expect(isProjectSettingsKey("persistAgentThinkingLogEphemeral")).toBe(false);
|
||||||
|
expect(isGlobalOnlySettingsKey("persistAgentThinkingLogEphemeral")).toBe(true);
|
||||||
expect(isGlobalSettingsKey("researchSettings")).toBe(false);
|
expect(isGlobalSettingsKey("researchSettings")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("defaults persisted thinking logs to disabled", () => {
|
it("defaults persisted thinking logs to disabled", () => {
|
||||||
expect(DEFAULT_GLOBAL_SETTINGS.persistAgentThinkingLog).toBe(false);
|
expect(DEFAULT_GLOBAL_SETTINGS.persistAgentThinkingLog).toBe(false);
|
||||||
|
expect(DEFAULT_GLOBAL_SETTINGS.persistAgentThinkingLogPermanent).toBe(false);
|
||||||
|
expect(DEFAULT_GLOBAL_SETTINGS.persistAgentThinkingLogEphemeral).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("includes heartbeatMultiplier in project defaults", () => {
|
it("includes heartbeatMultiplier in project defaults", () => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export { COLUMNS, DEFAULT_COLUMN, isColumn, normalizeColumn, COLUMN_LABELS, COLUMN_DESCRIPTIONS, VALID_TRANSITIONS, DEFAULT_SETTINGS, DEFAULT_GLOBAL_SETTINGS, DEFAULT_PROJECT_SETTINGS, GLOBAL_SETTINGS_KEYS, PROJECT_SETTINGS_KEYS, isGlobalSettingsKey, isProjectSettingsKey, THINKING_LEVELS, THEME_MODES, COLOR_THEMES, WORKFLOW_STEP_TEMPLATES, AGENT_PERMISSIONS, PERMANENT_AGENT_ACTION_CATEGORIES, AGENT_PERMISSION_POLICY_ACTION_CATEGORIES, AGENT_PROVISIONING_APPROVAL_MODES, AGENT_PERMISSION_POLICY_PRESET_IDS, LEGACY_AGENT_PERMISSION_POLICY_ACTION_CATEGORY_ALIASES, APPROVAL_REQUEST_STATUSES, APPROVAL_REQUEST_AUDIT_EVENT_TYPES, normalizeApprovalRequestActionCategory, isValidApprovalRequestTransition, agentToConfigSnapshot, diffConfigSnapshots, isEphemeralAgent, hasAgentIdentity, CheckoutConflictError, DEFAULT_HEARTBEAT_PROCEDURE_PATH, getDefaultHeartbeatProcedurePath, EXECUTION_MODES, DEFAULT_EXECUTION_MODE, TASK_PRIORITIES, DEFAULT_TASK_PRIORITY, HIGH_FANOUT_BLOCKER_TODO_THRESHOLD, STALE_HIGH_FANOUT_BLOCKER_AGE_THRESHOLD_MS, DASHBOARD_USER_ID, normalizeMessageParticipant, validateMessageMetadata, validateDockerNodeConfig, sanitizeDockerNodeConfigForResponse, normalizeMergeConflictStrategy, normalizeMergeStrategyOverlapBehavior, buildResearchDocumentKey, REPO_OVERRIDE_RE, SHARED_STATE_SNAPSHOT_VERSION } from "./types.js";
|
export { COLUMNS, DEFAULT_COLUMN, isColumn, normalizeColumn, COLUMN_LABELS, COLUMN_DESCRIPTIONS, VALID_TRANSITIONS, DEFAULT_SETTINGS, DEFAULT_GLOBAL_SETTINGS, DEFAULT_PROJECT_SETTINGS, GLOBAL_SETTINGS_KEYS, PROJECT_SETTINGS_KEYS, isGlobalSettingsKey, isProjectSettingsKey, resolvePersistAgentThinkingLog, THINKING_LEVELS, THEME_MODES, COLOR_THEMES, WORKFLOW_STEP_TEMPLATES, AGENT_PERMISSIONS, PERMANENT_AGENT_ACTION_CATEGORIES, AGENT_PERMISSION_POLICY_ACTION_CATEGORIES, AGENT_PROVISIONING_APPROVAL_MODES, AGENT_PERMISSION_POLICY_PRESET_IDS, LEGACY_AGENT_PERMISSION_POLICY_ACTION_CATEGORY_ALIASES, APPROVAL_REQUEST_STATUSES, APPROVAL_REQUEST_AUDIT_EVENT_TYPES, normalizeApprovalRequestActionCategory, isValidApprovalRequestTransition, agentToConfigSnapshot, diffConfigSnapshots, isEphemeralAgent, hasAgentIdentity, CheckoutConflictError, DEFAULT_HEARTBEAT_PROCEDURE_PATH, getDefaultHeartbeatProcedurePath, EXECUTION_MODES, DEFAULT_EXECUTION_MODE, TASK_PRIORITIES, DEFAULT_TASK_PRIORITY, HIGH_FANOUT_BLOCKER_TODO_THRESHOLD, STALE_HIGH_FANOUT_BLOCKER_AGE_THRESHOLD_MS, DASHBOARD_USER_ID, normalizeMessageParticipant, validateMessageMetadata, validateDockerNodeConfig, sanitizeDockerNodeConfigForResponse, normalizeMergeConflictStrategy, normalizeMergeStrategyOverlapBehavior, buildResearchDocumentKey, REPO_OVERRIDE_RE, SHARED_STATE_SNAPSHOT_VERSION } from "./types.js";
|
||||||
export type { Column, IssueInfo, IssueState, TaskSourceIssue, PrInfo, PrStatus, Task, TaskTokenUsage, TaskAttachment, TaskComment, TaskCommentInput, TaskDocument, TaskDocumentRevision, TaskDocumentCreateInput, TaskDocumentWithTask, TaskCreateInput, MeshReplicatedTaskCreatePayload, MeshReplicatedTaskApplyResult, TaskSource, SourceType, TaskDetail, InboxTask, TodoList, TodoItem, TodoListCreateInput, TodoListUpdateInput, TodoItemCreateInput, TodoItemUpdateInput, TodoListWithItems, AgentLogEntry, AgentLogType, AgentRole, BoardConfig, DistributedTaskIdReserveInput, DistributedTaskIdReserveResult, DistributedTaskIdCommitInput, DistributedTaskIdCommitResult, DistributedTaskIdAbortInput, DistributedTaskIdAbortResult, DistributedTaskIdStateInput, DistributedTaskIdStateResult, AutostashOrphanRecord, AutostashOutcome, MergeDetails, MergeResult, MergeConflictStrategy, CanonicalMergeConflictStrategy, MergeStrategyOverlapBehavior, DirectMergeCommitStrategy, Settings, GlobalSettings, ProjectSettings, WebSearchBackend, ResearchEnabledSources, ResearchGlobalDefaults, ResearchProjectLimits, ResearchProjectSettings, EvalFollowUpPolicy, EvalProjectSettings, ResolvedEvalSettings, SettingsScope, DaemonTokenSettings, TaskStep, StepStatus, TaskLogEntry, RunMutationContext, ActivityLogEntry, ActivityEventType, ThinkingLevel, ThemeMode, ColorTheme, ExecutionMode, TaskPriority, UnavailableNodePolicy, PlanningQuestion, PlanningSummary, PlanningResponse, PlanningQuestionType, ArchivedTaskEntry, BatchStatusRequest, BatchStatusResponse, BatchStatusEntry, BatchStatusResult, ModelPreset, WorkflowStep, WorkflowStepMode, WorkflowStepPhase, WorkflowStepInput, WorkflowStepResult, WorkflowStepTemplate, Agent, OrgTreeNode, AgentState, AgentDetail, AgentCreateInput, AgentUpdateInput, AgentApiKey, AgentApiKeyCreateResult, AgentCapability, AgentPromptTemplate, AgentPromptsConfig, AgentPermission, PermanentAgentActionCategory, PermanentAgentSensitiveActionCategory, PermanentAgentGatingContext, AgentPermissionPolicy, AgentPermissionPolicyRules, AgentPermissionPolicyActionCategory, AgentProvisioningApprovalMode, LegacyAgentPermissionPolicyActionCategory, ApprovalRequestActionCategoryInput, ApprovalRequestActionCategory, AgentPermissionPolicyDisposition, AgentPermissionPolicyPresetId, ApprovalRequestStatus, ApprovalRequestAuditEventType, ApprovalRequestActorSnapshot, ApprovalRequestTargetAction, ApprovalRequestAuditEvent, ApprovalRequest, ApprovalRequestCreateInput, ApprovalRequestDecisionInput, ApprovalRequestCompletionInput, ApprovalRequestListInput, TaskAssignSource, AgentAccessState, AgentHeartbeatConfig, AgentBudgetConfig, AgentBudgetStatus, InstructionsBundleConfig, MessageResponseMode, AgentHeartbeatEvent, AgentHeartbeatRun, BlockedStateSnapshot, HeartbeatInvocationSource, AgentTaskSession, AgentRating, AgentRatingSummary, AgentRatingInput, AgentConfigSnapshot, RevisionFieldDiff, AgentConfigRevision, AgentStats, ReflectionTrigger, ReflectionMetrics, AgentReflection, AgentPerformanceSummary, NtfyNotificationEvent, NotificationEvent, NotificationPayload, NotificationProviderConfig, CustomProvider, SteeringComment, ParticipantType, MessageType, Message, MessageCreateInput, MessageFilter, MessageMetadata, MessageReplyReference, Mailbox, CheckoutLease, RunAuditDomain, RunAuditEvent, RunAuditEventInput, RunAuditEventFilter } from "./types.js";
|
export type { Column, IssueInfo, IssueState, TaskSourceIssue, PrInfo, PrStatus, Task, TaskTokenUsage, TaskAttachment, TaskComment, TaskCommentInput, TaskDocument, TaskDocumentRevision, TaskDocumentCreateInput, TaskDocumentWithTask, TaskCreateInput, MeshReplicatedTaskCreatePayload, MeshReplicatedTaskApplyResult, TaskSource, SourceType, TaskDetail, InboxTask, TodoList, TodoItem, TodoListCreateInput, TodoListUpdateInput, TodoItemCreateInput, TodoItemUpdateInput, TodoListWithItems, AgentLogEntry, AgentLogType, AgentRole, BoardConfig, DistributedTaskIdReserveInput, DistributedTaskIdReserveResult, DistributedTaskIdCommitInput, DistributedTaskIdCommitResult, DistributedTaskIdAbortInput, DistributedTaskIdAbortResult, DistributedTaskIdStateInput, DistributedTaskIdStateResult, AutostashOrphanRecord, AutostashOutcome, MergeDetails, MergeResult, MergeConflictStrategy, CanonicalMergeConflictStrategy, MergeStrategyOverlapBehavior, DirectMergeCommitStrategy, Settings, GlobalSettings, ProjectSettings, WebSearchBackend, ResearchEnabledSources, ResearchGlobalDefaults, ResearchProjectLimits, ResearchProjectSettings, EvalFollowUpPolicy, EvalProjectSettings, ResolvedEvalSettings, SettingsScope, DaemonTokenSettings, TaskStep, StepStatus, TaskLogEntry, RunMutationContext, ActivityLogEntry, ActivityEventType, ThinkingLevel, ThemeMode, ColorTheme, ExecutionMode, TaskPriority, UnavailableNodePolicy, PlanningQuestion, PlanningSummary, PlanningResponse, PlanningQuestionType, ArchivedTaskEntry, BatchStatusRequest, BatchStatusResponse, BatchStatusEntry, BatchStatusResult, ModelPreset, WorkflowStep, WorkflowStepMode, WorkflowStepPhase, WorkflowStepInput, WorkflowStepResult, WorkflowStepTemplate, Agent, OrgTreeNode, AgentState, AgentDetail, AgentCreateInput, AgentUpdateInput, AgentApiKey, AgentApiKeyCreateResult, AgentCapability, AgentPromptTemplate, AgentPromptsConfig, AgentPermission, PermanentAgentActionCategory, PermanentAgentSensitiveActionCategory, PermanentAgentGatingContext, AgentPermissionPolicy, AgentPermissionPolicyRules, AgentPermissionPolicyActionCategory, AgentProvisioningApprovalMode, LegacyAgentPermissionPolicyActionCategory, ApprovalRequestActionCategoryInput, ApprovalRequestActionCategory, AgentPermissionPolicyDisposition, AgentPermissionPolicyPresetId, ApprovalRequestStatus, ApprovalRequestAuditEventType, ApprovalRequestActorSnapshot, ApprovalRequestTargetAction, ApprovalRequestAuditEvent, ApprovalRequest, ApprovalRequestCreateInput, ApprovalRequestDecisionInput, ApprovalRequestCompletionInput, ApprovalRequestListInput, TaskAssignSource, AgentAccessState, AgentHeartbeatConfig, AgentBudgetConfig, AgentBudgetStatus, InstructionsBundleConfig, MessageResponseMode, AgentHeartbeatEvent, AgentHeartbeatRun, BlockedStateSnapshot, HeartbeatInvocationSource, AgentTaskSession, AgentRating, AgentRatingSummary, AgentRatingInput, AgentConfigSnapshot, RevisionFieldDiff, AgentConfigRevision, AgentStats, ReflectionTrigger, ReflectionMetrics, AgentReflection, AgentPerformanceSummary, NtfyNotificationEvent, NotificationEvent, NotificationPayload, NotificationProviderConfig, CustomProvider, SteeringComment, ParticipantType, MessageType, Message, MessageCreateInput, MessageFilter, MessageMetadata, MessageReplyReference, Mailbox, CheckoutLease, RunAuditDomain, RunAuditEvent, RunAuditEventInput, RunAuditEventFilter } from "./types.js";
|
||||||
export { AGENT_VALID_TRANSITIONS } from "./types.js";
|
export { AGENT_VALID_TRANSITIONS } from "./types.js";
|
||||||
export type { TaskReviewData, TaskReviewSummary, TaskReviewItem } from "./types.js";
|
export type { TaskReviewData, TaskReviewSummary, TaskReviewItem } from "./types.js";
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ export const DEFAULT_GLOBAL_SETTINGS = {
|
|||||||
vitestKillThresholdPct: 90,
|
vitestKillThresholdPct: 90,
|
||||||
// Agent log persistence controls
|
// Agent log persistence controls
|
||||||
persistAgentToolOutput: true,
|
persistAgentToolOutput: true,
|
||||||
|
persistAgentThinkingLogPermanent: false,
|
||||||
|
persistAgentThinkingLogEphemeral: false,
|
||||||
persistAgentThinkingLog: false,
|
persistAgentThinkingLog: false,
|
||||||
researchGlobalDefaults: {
|
researchGlobalDefaults: {
|
||||||
searchProvider: undefined,
|
searchProvider: undefined,
|
||||||
@@ -363,3 +365,16 @@ export function isProjectSettingsKey(key: string): key is keyof ProjectSettings
|
|||||||
export function isGlobalOnlySettingsKey(key: string): key is keyof GlobalSettings {
|
export function isGlobalOnlySettingsKey(key: string): key is keyof GlobalSettings {
|
||||||
return isGlobalSettingsKey(key) && !isProjectSettingsKey(key);
|
return isGlobalSettingsKey(key) && !isProjectSettingsKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function resolvePersistAgentThinkingLog(
|
||||||
|
settings: Partial<GlobalSettings> | undefined,
|
||||||
|
opts: { ephemeral: boolean },
|
||||||
|
): boolean {
|
||||||
|
const granular = opts.ephemeral
|
||||||
|
? settings?.persistAgentThinkingLogEphemeral
|
||||||
|
: settings?.persistAgentThinkingLogPermanent;
|
||||||
|
|
||||||
|
if (typeof granular === "boolean") return granular;
|
||||||
|
if (typeof settings?.persistAgentThinkingLog === "boolean") return settings.persistAgentThinkingLog;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1860,9 +1860,18 @@ export interface GlobalSettings {
|
|||||||
* verbose `detail` payload is omitted to reduce log size/noise. Distinct
|
* verbose `detail` payload is omitted to reduce log size/noise. Distinct
|
||||||
* from `persistAgentThinkingLog`, which controls `thinking` rows. */
|
* from `persistAgentThinkingLog`, which controls `thinking` rows. */
|
||||||
persistAgentToolOutput?: boolean;
|
persistAgentToolOutput?: boolean;
|
||||||
/** When true, persist `thinking` log entries from agent reasoning deltas.
|
/** When true, persist `thinking` log entries from agent reasoning deltas for
|
||||||
* Default: false (suppressed). This only affects persisted `thinking` rows
|
* permanent (non-ephemeral) agents. Default: false (suppressed). */
|
||||||
* and does not change normal assistant text/tool output behavior. */
|
persistAgentThinkingLogPermanent?: boolean;
|
||||||
|
/** When true, persist `thinking` log entries from agent reasoning deltas for
|
||||||
|
* ephemeral / task-worker / spawned agents. Default: false (suppressed). */
|
||||||
|
persistAgentThinkingLogEphemeral?: boolean;
|
||||||
|
/** @deprecated Use `persistAgentThinkingLogPermanent` and
|
||||||
|
* `persistAgentThinkingLogEphemeral` instead.
|
||||||
|
*
|
||||||
|
* Legacy fallback: when explicitly set and one of the granular fields is
|
||||||
|
* undefined, this value seeds that undefined granular kind at read time.
|
||||||
|
* Default: false (suppressed). */
|
||||||
persistAgentThinkingLog?: boolean;
|
persistAgentThinkingLog?: boolean;
|
||||||
/** Research defaults shared across all projects.
|
/** Research defaults shared across all projects.
|
||||||
* Project settings may override these via `researchSettings`. */
|
* Project settings may override these via `researchSettings`. */
|
||||||
@@ -2557,6 +2566,7 @@ export {
|
|||||||
isGlobalOnlySettingsKey,
|
isGlobalOnlySettingsKey,
|
||||||
isGlobalSettingsKey,
|
isGlobalSettingsKey,
|
||||||
isProjectSettingsKey,
|
isProjectSettingsKey,
|
||||||
|
resolvePersistAgentThinkingLog,
|
||||||
} from "./settings-schema.js";
|
} from "./settings-schema.js";
|
||||||
|
|
||||||
export interface BoardConfig {
|
export interface BoardConfig {
|
||||||
|
|||||||
Reference in New Issue
Block a user