@swarmclawai/swarmclaw 1.2.8 → 1.2.9
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/README.md +30 -6
- package/package.json +2 -2
- package/src/app/agents/[id]/page.tsx +1 -18
- package/src/app/api/agents/thread-route.test.ts +0 -1
- package/src/app/api/approvals/route.test.ts +6 -22
- package/src/app/api/connectors/route.ts +2 -2
- package/src/app/api/portability/export/route.ts +8 -0
- package/src/app/api/portability/import/route.test.ts +80 -0
- package/src/app/api/portability/import/route.ts +28 -0
- package/src/app/api/settings/route.ts +0 -2
- package/src/app/api/wallets/[id]/route.ts +15 -157
- package/src/app/api/wallets/generate/route.ts +22 -0
- package/src/app/api/wallets/route.test.ts +147 -0
- package/src/app/api/wallets/route.ts +13 -95
- package/src/app/autonomy/page.tsx +2 -57
- package/src/app/protocols/page.tsx +2 -21
- package/src/app/settings/page.tsx +0 -9
- package/src/app/wallets/page.tsx +105 -5
- package/src/cli/index.js +21 -33
- package/src/cli/spec.js +19 -30
- package/src/components/agents/agent-sheet.tsx +2 -40
- package/src/components/agents/inspector-panel.tsx +0 -83
- package/src/components/chat/chat-card.tsx +0 -31
- package/src/components/chat/message-bubble.tsx +1 -108
- package/src/components/connectors/connector-sheet.tsx +25 -1
- package/src/components/layout/sidebar-rail.tsx +6 -10
- package/src/components/projects/project-detail.tsx +3 -35
- package/src/components/projects/tabs/overview-tab.tsx +3 -59
- package/src/components/projects/tabs/work-tab.tsx +7 -77
- package/src/components/protocols/structured-session-launcher.tsx +1 -22
- package/src/components/shared/connector-platform-icon.tsx +1 -0
- package/src/components/tasks/task-card.tsx +4 -34
- package/src/components/tasks/task-sheet.tsx +6 -36
- package/src/components/wallets/wallet-list.tsx +150 -0
- package/src/lib/app/navigation.test.ts +0 -13
- package/src/lib/app/navigation.ts +2 -7
- package/src/lib/app/view-constants.ts +14 -19
- package/src/lib/server/agents/agent-thread-session.ts +0 -1
- package/src/lib/server/agents/delegation-advisory.test.ts +0 -1
- package/src/lib/server/agents/delegation-jobs.test.ts +0 -69
- package/src/lib/server/agents/delegation-jobs.ts +0 -25
- package/src/lib/server/agents/main-agent-loop.ts +1 -49
- package/src/lib/server/agents/subagent-runtime.ts +0 -1
- package/src/lib/server/approval-match.ts +0 -85
- package/src/lib/server/approvals.test.ts +6 -6
- package/src/lib/server/approvals.ts +0 -6
- package/src/lib/server/autonomy/supervisor-reflection.test.ts +0 -1
- package/src/lib/server/builtin-extensions.ts +0 -2
- package/src/lib/server/capability-router.test.ts +0 -2
- package/src/lib/server/chat-execution/chat-execution-tool-events.test.ts +14 -14
- package/src/lib/server/chat-execution/chat-execution-types.ts +0 -2
- package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -2
- package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -30
- package/src/lib/server/chat-execution/chat-turn-finalization.ts +1 -36
- package/src/lib/server/chat-execution/chat-turn-preparation.ts +2 -22
- package/src/lib/server/chat-execution/iteration-event-handler.ts +0 -24
- package/src/lib/server/chat-execution/message-classifier.test.ts +0 -45
- package/src/lib/server/chat-execution/message-classifier.ts +1 -16
- package/src/lib/server/chat-execution/prompt-builder.test.ts +0 -1
- package/src/lib/server/chat-execution/prompt-builder.ts +0 -30
- package/src/lib/server/chat-execution/prompt-sections.ts +0 -1
- package/src/lib/server/chat-execution/situational-awareness.test.ts +2 -73
- package/src/lib/server/chat-execution/situational-awareness.ts +4 -38
- package/src/lib/server/chat-execution/stream-agent-chat.test.ts +8 -123
- package/src/lib/server/chat-execution/stream-agent-chat.ts +1 -5
- package/src/lib/server/chat-execution/stream-continuation.test.ts +4 -52
- package/src/lib/server/chat-execution/stream-continuation.ts +6 -48
- package/src/lib/server/chatrooms/session-mailbox.ts +0 -10
- package/src/lib/server/chats/chat-session-service.ts +3 -5
- package/src/lib/server/connectors/connector-inbound.ts +0 -1
- package/src/lib/server/connectors/connector-lifecycle.ts +19 -3
- package/src/lib/server/connectors/connector-service.ts +39 -9
- package/src/lib/server/connectors/swarmdock-bidding.ts +74 -0
- package/src/lib/server/connectors/swarmdock-payloads.test.ts +85 -0
- package/src/lib/server/connectors/swarmdock-secret.test.ts +128 -0
- package/src/lib/server/connectors/swarmdock-secret.ts +152 -0
- package/src/lib/server/connectors/swarmdock-tasks.ts +119 -0
- package/src/lib/server/connectors/swarmdock.ts +255 -0
- package/src/lib/server/execution-brief.test.ts +2 -25
- package/src/lib/server/execution-brief.ts +12 -35
- package/src/lib/server/execution-engine/task-attempt.ts +0 -1
- package/src/lib/server/persistence/storage-context.ts +0 -5
- package/src/lib/server/portability/export.ts +109 -0
- package/src/lib/server/portability/import.ts +159 -0
- package/src/lib/server/protocols/protocol-normalization.ts +0 -4
- package/src/lib/server/protocols/protocol-queries.ts +0 -6
- package/src/lib/server/protocols/protocol-run-lifecycle.ts +4 -32
- package/src/lib/server/protocols/protocol-service.ts +0 -1
- package/src/lib/server/protocols/protocol-step-helpers.ts +0 -4
- package/src/lib/server/protocols/protocol-step-processors.ts +0 -6
- package/src/lib/server/protocols/protocol-swarm.ts +0 -2
- package/src/lib/server/protocols/protocol-types.ts +0 -2
- package/src/lib/server/provider-health.ts +0 -9
- package/src/lib/server/runtime/daemon-state/core.ts +0 -9
- package/src/lib/server/runtime/daemon-state.test.ts +0 -35
- package/src/lib/server/runtime/heartbeat-service.ts +3 -23
- package/src/lib/server/runtime/queue/core.ts +11 -33
- package/src/lib/server/runtime/runtime-storage-write-paths.test.ts +6 -6
- package/src/lib/server/runtime/scheduler.ts +0 -13
- package/src/lib/server/runtime/session-run-manager/drain.ts +0 -24
- package/src/lib/server/runtime/session-run-manager/enqueue.ts +0 -1
- package/src/lib/server/runtime/session-run-manager/queries.ts +0 -1
- package/src/lib/server/runtime/session-run-manager/recovery.ts +0 -1
- package/src/lib/server/runtime/session-run-manager.test.ts +0 -28
- package/src/lib/server/session-tools/crud.ts +0 -14
- package/src/lib/server/session-tools/delegate.ts +0 -4
- package/src/lib/server/session-tools/index.ts +0 -4
- package/src/lib/server/session-tools/team-context.ts +0 -3
- package/src/lib/server/storage-normalization.ts +8 -0
- package/src/lib/server/storage.ts +18 -45
- package/src/lib/server/tasks/task-checkout.ts +59 -0
- package/src/lib/server/tasks/task-lifecycle.ts +2 -0
- package/src/lib/server/tasks/task-route-service.ts +4 -26
- package/src/lib/server/tasks/task-service.ts +0 -7
- package/src/lib/server/tool-aliases.ts +0 -1
- package/src/lib/server/tool-capability-policy-advanced.test.ts +4 -4
- package/src/lib/server/tool-capability-policy.ts +0 -2
- package/src/lib/server/tool-planning.ts +0 -12
- package/src/lib/server/universal-tool-access.ts +0 -1
- package/src/lib/server/wallets/wallet-crypto.ts +33 -0
- package/src/lib/server/wallets/wallet-repository.ts +24 -0
- package/src/lib/server/wallets/wallet-service.ts +119 -0
- package/src/lib/server/working-state/extraction.ts +8 -42
- package/src/lib/server/working-state/normalization.ts +10 -103
- package/src/lib/server/working-state/service.ts +12 -21
- package/src/lib/strip-internal-metadata.test.ts +1 -1
- package/src/lib/strip-internal-metadata.ts +1 -1
- package/src/lib/tool-definitions.ts +0 -1
- package/src/lib/validation/schemas.ts +33 -2
- package/src/stores/slices/data-slice.ts +5 -1
- package/src/stores/slices/ui-slice.ts +0 -4
- package/src/types/agent.ts +0 -84
- package/src/types/app-settings.ts +0 -2
- package/src/types/approval.ts +0 -2
- package/src/types/connector.ts +1 -0
- package/src/types/index.ts +1 -1
- package/src/types/message.ts +0 -1
- package/src/types/misc.ts +0 -2
- package/src/types/protocol.ts +0 -2
- package/src/types/run.ts +0 -3
- package/src/types/session.ts +1 -51
- package/src/types/swarmdock.ts +29 -0
- package/src/types/task.ts +7 -3
- package/src/types/working-state.ts +2 -9
- package/src/views/settings/section-runtime-loop.tsx +0 -14
- package/src/app/api/canvas/[sessionId]/route.ts +0 -35
- package/src/app/api/missions/[id]/actions/route.ts +0 -31
- package/src/app/api/missions/[id]/events/route.ts +0 -14
- package/src/app/api/missions/[id]/route.ts +0 -10
- package/src/app/api/missions/route.test.ts +0 -244
- package/src/app/api/missions/route.ts +0 -57
- package/src/app/api/wallets/[id]/approve/route.ts +0 -79
- package/src/app/api/wallets/[id]/balance-history/route.ts +0 -18
- package/src/app/api/wallets/[id]/send/route.ts +0 -113
- package/src/app/api/wallets/[id]/transactions/route.ts +0 -18
- package/src/app/missions/[id]/page.tsx +0 -3
- package/src/app/missions/page.tsx +0 -685
- package/src/components/canvas/canvas-panel.tsx +0 -267
- package/src/components/wallets/wallet-approval-dialog.tsx +0 -107
- package/src/components/wallets/wallet-panel.tsx +0 -1010
- package/src/components/wallets/wallet-section.tsx +0 -260
- package/src/features/missions/queries.ts +0 -23
- package/src/lib/canvas-content.test.ts +0 -360
- package/src/lib/canvas-content.ts +0 -198
- package/src/lib/server/canvas-content.test.ts +0 -32
- package/src/lib/server/canvas-content.ts +0 -6
- package/src/lib/server/ethereum.ts +0 -591
- package/src/lib/server/evm-swap.ts +0 -476
- package/src/lib/server/missions/mission-intent.test.ts +0 -63
- package/src/lib/server/missions/mission-intent.ts +0 -569
- package/src/lib/server/missions/mission-repository.ts +0 -74
- package/src/lib/server/missions/mission-service/actions.ts +0 -6
- package/src/lib/server/missions/mission-service/bindings.ts +0 -9
- package/src/lib/server/missions/mission-service/context.ts +0 -4
- package/src/lib/server/missions/mission-service/core.ts +0 -2271
- package/src/lib/server/missions/mission-service/queries.ts +0 -12
- package/src/lib/server/missions/mission-service/recovery.ts +0 -5
- package/src/lib/server/missions/mission-service/ticks.ts +0 -9
- package/src/lib/server/missions/mission-service.test.ts +0 -888
- package/src/lib/server/missions/mission-service.ts +0 -6
- package/src/lib/server/session-tools/canvas.ts +0 -105
- package/src/lib/server/session-tools/wallet-tool.test.ts +0 -150
- package/src/lib/server/session-tools/wallet.ts +0 -1287
- package/src/lib/server/solana.ts +0 -327
- package/src/lib/server/wallet/wallet-execution.test.ts +0 -198
- package/src/lib/server/wallet/wallet-portfolio.test.ts +0 -98
- package/src/lib/server/wallet/wallet-portfolio.ts +0 -772
- package/src/lib/server/wallet/wallet-service.test.ts +0 -81
- package/src/lib/server/wallet/wallet-service.ts +0 -225
- package/src/lib/wallet/wallet-transactions.test.ts +0 -75
- package/src/lib/wallet/wallet-transactions.ts +0 -43
- package/src/lib/wallet/wallet.test.ts +0 -333
- package/src/lib/wallet/wallet.ts +0 -183
- package/src/types/mission.ts +0 -185
- package/src/views/settings/section-wallets.tsx +0 -35
|
@@ -1,569 +0,0 @@
|
|
|
1
|
-
import { HumanMessage } from '@langchain/core/messages'
|
|
2
|
-
import { z } from 'zod'
|
|
3
|
-
import type {
|
|
4
|
-
Message,
|
|
5
|
-
MessageToolEvent,
|
|
6
|
-
Mission,
|
|
7
|
-
MissionPhase,
|
|
8
|
-
MissionSummary,
|
|
9
|
-
MissionWaitKind,
|
|
10
|
-
Session,
|
|
11
|
-
SessionQueuedTurn,
|
|
12
|
-
SessionRunRecord,
|
|
13
|
-
} from '@/types'
|
|
14
|
-
import { buildLLM } from '@/lib/server/build-llm'
|
|
15
|
-
|
|
16
|
-
const MissionTurnDecisionSchema = z.object({
|
|
17
|
-
action: z.enum(['none', 'attach_current', 'create_new']),
|
|
18
|
-
confidence: z.number().min(0).max(1).optional(),
|
|
19
|
-
objective: z.string().optional().nullable(),
|
|
20
|
-
successCriteria: z.array(z.string()).optional(),
|
|
21
|
-
currentStep: z.string().optional().nullable(),
|
|
22
|
-
plannerSummary: z.string().optional().nullable(),
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
const MissionOutcomeSchema = z.object({
|
|
26
|
-
verdict: z.enum(['continue', 'waiting', 'completed', 'failed', 'replan']),
|
|
27
|
-
confidence: z.number().min(0).max(1).optional(),
|
|
28
|
-
phase: z.enum(['planning', 'executing', 'verifying', 'waiting', 'completed', 'failed']).optional(),
|
|
29
|
-
currentStep: z.string().optional().nullable(),
|
|
30
|
-
verifierSummary: z.string().optional().nullable(),
|
|
31
|
-
waitKind: z.enum(['human_reply', 'approval', 'external_dependency', 'provider', 'blocked_task', 'blocked_mission', 'scheduled', 'other']).optional(),
|
|
32
|
-
waitReason: z.string().optional().nullable(),
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
const MissionPlannerSchema = z.object({
|
|
36
|
-
decision: z.enum(['dispatch_task', 'dispatch_session_turn', 'spawn_child_mission', 'wait', 'verify_now', 'complete_candidate', 'replan', 'fail_terminal']),
|
|
37
|
-
confidence: z.number().min(0).max(1).optional(),
|
|
38
|
-
summary: z.string().optional().nullable(),
|
|
39
|
-
currentStep: z.string().optional().nullable(),
|
|
40
|
-
waitKind: z.enum(['human_reply', 'approval', 'external_dependency', 'provider', 'blocked_task', 'blocked_mission', 'scheduled', 'other']).optional(),
|
|
41
|
-
waitReason: z.string().optional().nullable(),
|
|
42
|
-
taskId: z.string().optional().nullable(),
|
|
43
|
-
sessionMessage: z.string().optional().nullable(),
|
|
44
|
-
childObjective: z.string().optional().nullable(),
|
|
45
|
-
childSuccessCriteria: z.array(z.string()).optional(),
|
|
46
|
-
childCurrentStep: z.string().optional().nullable(),
|
|
47
|
-
childPlannerSummary: z.string().optional().nullable(),
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
export type MissionTurnDecision =
|
|
51
|
-
| { action: 'none'; confidence: number }
|
|
52
|
-
| {
|
|
53
|
-
action: 'attach_current'
|
|
54
|
-
confidence: number
|
|
55
|
-
currentStep?: string
|
|
56
|
-
plannerSummary?: string
|
|
57
|
-
}
|
|
58
|
-
| {
|
|
59
|
-
action: 'create_new'
|
|
60
|
-
confidence: number
|
|
61
|
-
objective: string
|
|
62
|
-
successCriteria: string[]
|
|
63
|
-
currentStep?: string
|
|
64
|
-
plannerSummary?: string
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export type MissionOutcomeDecision = {
|
|
68
|
-
verdict: 'continue' | 'waiting' | 'completed' | 'failed' | 'replan'
|
|
69
|
-
confidence: number
|
|
70
|
-
phase?: MissionPhase
|
|
71
|
-
currentStep?: string
|
|
72
|
-
verifierSummary?: string
|
|
73
|
-
waitKind?: MissionWaitKind
|
|
74
|
-
waitReason?: string
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export type MissionPlannerDecisionResult =
|
|
78
|
-
| {
|
|
79
|
-
decision: 'dispatch_task'
|
|
80
|
-
confidence: number
|
|
81
|
-
summary?: string
|
|
82
|
-
currentStep?: string
|
|
83
|
-
taskId: string
|
|
84
|
-
}
|
|
85
|
-
| {
|
|
86
|
-
decision: 'dispatch_session_turn'
|
|
87
|
-
confidence: number
|
|
88
|
-
summary?: string
|
|
89
|
-
currentStep?: string
|
|
90
|
-
sessionMessage: string
|
|
91
|
-
}
|
|
92
|
-
| {
|
|
93
|
-
decision: 'spawn_child_mission'
|
|
94
|
-
confidence: number
|
|
95
|
-
summary?: string
|
|
96
|
-
currentStep?: string
|
|
97
|
-
childObjective: string
|
|
98
|
-
childSuccessCriteria: string[]
|
|
99
|
-
childCurrentStep?: string
|
|
100
|
-
childPlannerSummary?: string
|
|
101
|
-
}
|
|
102
|
-
| {
|
|
103
|
-
decision: 'wait'
|
|
104
|
-
confidence: number
|
|
105
|
-
summary?: string
|
|
106
|
-
currentStep?: string
|
|
107
|
-
waitKind?: MissionWaitKind
|
|
108
|
-
waitReason?: string
|
|
109
|
-
}
|
|
110
|
-
| {
|
|
111
|
-
decision: 'verify_now' | 'complete_candidate' | 'replan' | 'fail_terminal'
|
|
112
|
-
confidence: number
|
|
113
|
-
summary?: string
|
|
114
|
-
currentStep?: string
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export interface MissionTurnClassifierInput {
|
|
118
|
-
sessionId: string
|
|
119
|
-
agentId?: string | null
|
|
120
|
-
message: string
|
|
121
|
-
recentMessages?: Message[]
|
|
122
|
-
currentMission?: MissionSummary | Mission | null
|
|
123
|
-
session?: Session | null
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export interface MissionOutcomeClassifierInput {
|
|
127
|
-
sessionId: string
|
|
128
|
-
agentId?: string | null
|
|
129
|
-
userMessage: string
|
|
130
|
-
assistantText?: string | null
|
|
131
|
-
error?: string | null
|
|
132
|
-
toolEvents?: MessageToolEvent[]
|
|
133
|
-
currentMission: MissionSummary | Mission
|
|
134
|
-
linkedTaskSummaries?: Array<{
|
|
135
|
-
id: string
|
|
136
|
-
title: string
|
|
137
|
-
status: string
|
|
138
|
-
result?: string | null
|
|
139
|
-
error?: string | null
|
|
140
|
-
}>
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export interface MissionPlannerInput {
|
|
144
|
-
sessionId: string
|
|
145
|
-
agentId?: string | null
|
|
146
|
-
mission: MissionSummary | Mission
|
|
147
|
-
linkedTaskSummaries?: Array<{
|
|
148
|
-
id: string
|
|
149
|
-
title: string
|
|
150
|
-
status: string
|
|
151
|
-
result?: string | null
|
|
152
|
-
error?: string | null
|
|
153
|
-
}>
|
|
154
|
-
childMissionSummaries?: MissionSummary[]
|
|
155
|
-
recentRuns?: Array<Pick<SessionRunRecord, 'id' | 'status' | 'source' | 'queuedAt' | 'messagePreview' | 'resultPreview' | 'error'>>
|
|
156
|
-
queuedTurns?: Array<Pick<SessionQueuedTurn, 'runId' | 'text' | 'queuedAt' | 'source'>>
|
|
157
|
-
recentEvents?: Array<{
|
|
158
|
-
type: string
|
|
159
|
-
summary: string
|
|
160
|
-
createdAt: number
|
|
161
|
-
}>
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function normalizeText(value: unknown, max = 400): string {
|
|
165
|
-
return typeof value === 'string' ? value.replace(/\s+/g, ' ').trim().slice(0, max) : ''
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function normalizeLines(values: unknown, maxItems: number, maxChars = 160): string[] {
|
|
169
|
-
const source = Array.isArray(values) ? values : []
|
|
170
|
-
const seen = new Set<string>()
|
|
171
|
-
const out: string[] = []
|
|
172
|
-
for (const value of source) {
|
|
173
|
-
const normalized = normalizeText(value, maxChars)
|
|
174
|
-
if (!normalized) continue
|
|
175
|
-
const key = normalized.toLowerCase()
|
|
176
|
-
if (seen.has(key)) continue
|
|
177
|
-
seen.add(key)
|
|
178
|
-
out.push(normalized)
|
|
179
|
-
if (out.length >= maxItems) break
|
|
180
|
-
}
|
|
181
|
-
return out
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function extractModelText(content: unknown): string {
|
|
185
|
-
if (typeof content === 'string') return content
|
|
186
|
-
if (!Array.isArray(content)) return ''
|
|
187
|
-
return content
|
|
188
|
-
.map((part) => (part && typeof part === 'object' && 'text' in part && typeof part.text === 'string') ? part.text : '')
|
|
189
|
-
.join('')
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function extractFirstJsonObject(text: string): string | null {
|
|
193
|
-
const source = normalizeText(text, 12_000)
|
|
194
|
-
if (!source) return null
|
|
195
|
-
let start = -1
|
|
196
|
-
let depth = 0
|
|
197
|
-
let inString = false
|
|
198
|
-
let escaped = false
|
|
199
|
-
for (let index = 0; index < source.length; index += 1) {
|
|
200
|
-
const char = source[index]
|
|
201
|
-
if (start === -1) {
|
|
202
|
-
if (char === '{') {
|
|
203
|
-
start = index
|
|
204
|
-
depth = 1
|
|
205
|
-
}
|
|
206
|
-
continue
|
|
207
|
-
}
|
|
208
|
-
if (inString) {
|
|
209
|
-
if (escaped) escaped = false
|
|
210
|
-
else if (char === '\\') escaped = true
|
|
211
|
-
else if (char === '"') inString = false
|
|
212
|
-
continue
|
|
213
|
-
}
|
|
214
|
-
if (char === '"') {
|
|
215
|
-
inString = true
|
|
216
|
-
continue
|
|
217
|
-
}
|
|
218
|
-
if (char === '{') depth += 1
|
|
219
|
-
else if (char === '}') depth -= 1
|
|
220
|
-
if (depth === 0) return source.slice(start, index + 1)
|
|
221
|
-
}
|
|
222
|
-
return null
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function parseJsonObject(text: string): Record<string, unknown> | null {
|
|
226
|
-
try {
|
|
227
|
-
const parsed = JSON.parse(text) as unknown
|
|
228
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return null
|
|
229
|
-
return parsed as Record<string, unknown>
|
|
230
|
-
} catch {
|
|
231
|
-
return null
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
export function parseMissionTurnDecision(text: string): MissionTurnDecision | null {
|
|
236
|
-
const jsonText = extractFirstJsonObject(text)
|
|
237
|
-
if (!jsonText) return null
|
|
238
|
-
const jsonValue = parseJsonObject(jsonText)
|
|
239
|
-
if (!jsonValue) return null
|
|
240
|
-
const parsed = MissionTurnDecisionSchema.safeParse(jsonValue)
|
|
241
|
-
if (!parsed.success) return null
|
|
242
|
-
const confidence = typeof parsed.data.confidence === 'number' ? parsed.data.confidence : 0
|
|
243
|
-
if (parsed.data.action === 'none') return { action: 'none', confidence }
|
|
244
|
-
if (parsed.data.action === 'attach_current') {
|
|
245
|
-
return {
|
|
246
|
-
action: 'attach_current',
|
|
247
|
-
confidence,
|
|
248
|
-
...(normalizeText(parsed.data.currentStep, 200) ? { currentStep: normalizeText(parsed.data.currentStep, 200) } : {}),
|
|
249
|
-
...(normalizeText(parsed.data.plannerSummary, 320) ? { plannerSummary: normalizeText(parsed.data.plannerSummary, 320) } : {}),
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
const objective = normalizeText(parsed.data.objective, 300)
|
|
253
|
-
if (!objective) return null
|
|
254
|
-
return {
|
|
255
|
-
action: 'create_new',
|
|
256
|
-
confidence,
|
|
257
|
-
objective,
|
|
258
|
-
successCriteria: normalizeLines(parsed.data.successCriteria, 6, 180),
|
|
259
|
-
...(normalizeText(parsed.data.currentStep, 200) ? { currentStep: normalizeText(parsed.data.currentStep, 200) } : {}),
|
|
260
|
-
...(normalizeText(parsed.data.plannerSummary, 320) ? { plannerSummary: normalizeText(parsed.data.plannerSummary, 320) } : {}),
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export function parseMissionOutcomeDecision(text: string): MissionOutcomeDecision | null {
|
|
265
|
-
const jsonText = extractFirstJsonObject(text)
|
|
266
|
-
if (!jsonText) return null
|
|
267
|
-
const jsonValue = parseJsonObject(jsonText)
|
|
268
|
-
if (!jsonValue) return null
|
|
269
|
-
const parsed = MissionOutcomeSchema.safeParse(jsonValue)
|
|
270
|
-
if (!parsed.success) return null
|
|
271
|
-
return {
|
|
272
|
-
verdict: parsed.data.verdict,
|
|
273
|
-
confidence: typeof parsed.data.confidence === 'number' ? parsed.data.confidence : 0,
|
|
274
|
-
...(parsed.data.phase ? { phase: parsed.data.phase } : {}),
|
|
275
|
-
...(normalizeText(parsed.data.currentStep, 200) ? { currentStep: normalizeText(parsed.data.currentStep, 200) } : {}),
|
|
276
|
-
...(normalizeText(parsed.data.verifierSummary, 360) ? { verifierSummary: normalizeText(parsed.data.verifierSummary, 360) } : {}),
|
|
277
|
-
...(parsed.data.waitKind ? { waitKind: parsed.data.waitKind } : {}),
|
|
278
|
-
...(normalizeText(parsed.data.waitReason, 240) ? { waitReason: normalizeText(parsed.data.waitReason, 240) } : {}),
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
export function parseMissionPlannerDecision(text: string): MissionPlannerDecisionResult | null {
|
|
283
|
-
const jsonText = extractFirstJsonObject(text)
|
|
284
|
-
if (!jsonText) return null
|
|
285
|
-
const jsonValue = parseJsonObject(jsonText)
|
|
286
|
-
if (!jsonValue) return null
|
|
287
|
-
const parsed = MissionPlannerSchema.safeParse(jsonValue)
|
|
288
|
-
if (!parsed.success) return null
|
|
289
|
-
const confidence = typeof parsed.data.confidence === 'number' ? parsed.data.confidence : 0
|
|
290
|
-
const summary = normalizeText(parsed.data.summary, 360) || undefined
|
|
291
|
-
const currentStep = normalizeText(parsed.data.currentStep, 200) || undefined
|
|
292
|
-
|
|
293
|
-
if (parsed.data.decision === 'dispatch_task') {
|
|
294
|
-
const taskId = normalizeText(parsed.data.taskId, 64)
|
|
295
|
-
if (!taskId) return null
|
|
296
|
-
return {
|
|
297
|
-
decision: 'dispatch_task',
|
|
298
|
-
confidence,
|
|
299
|
-
...(summary ? { summary } : {}),
|
|
300
|
-
...(currentStep ? { currentStep } : {}),
|
|
301
|
-
taskId,
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
if (parsed.data.decision === 'dispatch_session_turn') {
|
|
306
|
-
const sessionMessage = normalizeText(parsed.data.sessionMessage, 1600)
|
|
307
|
-
if (!sessionMessage) return null
|
|
308
|
-
return {
|
|
309
|
-
decision: 'dispatch_session_turn',
|
|
310
|
-
confidence,
|
|
311
|
-
...(summary ? { summary } : {}),
|
|
312
|
-
...(currentStep ? { currentStep } : {}),
|
|
313
|
-
sessionMessage,
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (parsed.data.decision === 'spawn_child_mission') {
|
|
318
|
-
const childObjective = normalizeText(parsed.data.childObjective, 300)
|
|
319
|
-
if (!childObjective) return null
|
|
320
|
-
return {
|
|
321
|
-
decision: 'spawn_child_mission',
|
|
322
|
-
confidence,
|
|
323
|
-
...(summary ? { summary } : {}),
|
|
324
|
-
...(currentStep ? { currentStep } : {}),
|
|
325
|
-
childObjective,
|
|
326
|
-
childSuccessCriteria: normalizeLines(parsed.data.childSuccessCriteria, 6, 180),
|
|
327
|
-
...(normalizeText(parsed.data.childCurrentStep, 200) ? { childCurrentStep: normalizeText(parsed.data.childCurrentStep, 200) } : {}),
|
|
328
|
-
...(normalizeText(parsed.data.childPlannerSummary, 320) ? { childPlannerSummary: normalizeText(parsed.data.childPlannerSummary, 320) } : {}),
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (parsed.data.decision === 'wait') {
|
|
333
|
-
return {
|
|
334
|
-
decision: 'wait',
|
|
335
|
-
confidence,
|
|
336
|
-
...(summary ? { summary } : {}),
|
|
337
|
-
...(currentStep ? { currentStep } : {}),
|
|
338
|
-
...(parsed.data.waitKind ? { waitKind: parsed.data.waitKind } : {}),
|
|
339
|
-
...(normalizeText(parsed.data.waitReason, 240) ? { waitReason: normalizeText(parsed.data.waitReason, 240) } : {}),
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
return {
|
|
344
|
-
decision: parsed.data.decision,
|
|
345
|
-
confidence,
|
|
346
|
-
...(summary ? { summary } : {}),
|
|
347
|
-
...(currentStep ? { currentStep } : {}),
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
function buildRecentMessageContext(messages: Message[] | undefined): string {
|
|
352
|
-
if (!Array.isArray(messages) || messages.length === 0) return '(none)'
|
|
353
|
-
return messages.slice(-6).map((message) => {
|
|
354
|
-
const role = message.role === 'assistant' ? 'assistant' : 'user'
|
|
355
|
-
return `- ${role}: ${JSON.stringify(normalizeText(message.text, 220) || '(empty)')}`
|
|
356
|
-
}).join('\n')
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
function summarizeMission(mission: MissionSummary | Mission | null | undefined): string {
|
|
360
|
-
if (!mission) return '(none)'
|
|
361
|
-
const rawSuccessCriteria = 'successCriteria' in mission ? mission.successCriteria : undefined
|
|
362
|
-
const successCriteria = Array.isArray(rawSuccessCriteria) && rawSuccessCriteria.length > 0
|
|
363
|
-
? rawSuccessCriteria.join(' | ')
|
|
364
|
-
: '(none)'
|
|
365
|
-
return [
|
|
366
|
-
`objective=${JSON.stringify(normalizeText(mission.objective, 260) || '(none)')}`,
|
|
367
|
-
`status=${mission.status}`,
|
|
368
|
-
`phase=${mission.phase}`,
|
|
369
|
-
`current_step=${JSON.stringify(normalizeText(mission.currentStep, 160) || '(none)')}`,
|
|
370
|
-
`success_criteria=${JSON.stringify(successCriteria)}`,
|
|
371
|
-
].join('\n')
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
function summarizeToolEvents(toolEvents: MessageToolEvent[] | undefined): string {
|
|
375
|
-
if (!Array.isArray(toolEvents) || toolEvents.length === 0) return '(none)'
|
|
376
|
-
return toolEvents.slice(0, 8).map((event) => JSON.stringify({
|
|
377
|
-
name: normalizeText(event.name, 120) || 'unknown',
|
|
378
|
-
input: normalizeText(event.input, 160) || null,
|
|
379
|
-
output: normalizeText(event.output, 220) || null,
|
|
380
|
-
error: event.error === true,
|
|
381
|
-
})).join('\n')
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
function summarizeLinkedTasks(input: MissionOutcomeClassifierInput['linkedTaskSummaries']): string {
|
|
385
|
-
if (!Array.isArray(input) || input.length === 0) return '(none)'
|
|
386
|
-
return input.slice(0, 8).map((task) => JSON.stringify({
|
|
387
|
-
id: task.id,
|
|
388
|
-
title: normalizeText(task.title, 160),
|
|
389
|
-
status: task.status,
|
|
390
|
-
result: normalizeText(task.result, 180) || null,
|
|
391
|
-
error: normalizeText(task.error, 180) || null,
|
|
392
|
-
})).join('\n')
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
function summarizeChildMissions(children: MissionSummary[] | undefined): string {
|
|
396
|
-
if (!Array.isArray(children) || children.length === 0) return '(none)'
|
|
397
|
-
return children.slice(0, 8).map((child) => JSON.stringify({
|
|
398
|
-
id: child.id,
|
|
399
|
-
objective: normalizeText(child.objective, 180),
|
|
400
|
-
status: child.status,
|
|
401
|
-
phase: child.phase,
|
|
402
|
-
currentStep: normalizeText(child.currentStep, 140) || null,
|
|
403
|
-
waitingReason: normalizeText(child.waitingReason, 160) || null,
|
|
404
|
-
})).join('\n')
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
function summarizeRecentRuns(runs: MissionPlannerInput['recentRuns']): string {
|
|
408
|
-
if (!Array.isArray(runs) || runs.length === 0) return '(none)'
|
|
409
|
-
return runs.slice(0, 6).map((run) => JSON.stringify({
|
|
410
|
-
id: run.id,
|
|
411
|
-
status: run.status,
|
|
412
|
-
source: run.source,
|
|
413
|
-
queuedAt: run.queuedAt,
|
|
414
|
-
messagePreview: normalizeText(run.messagePreview, 180) || null,
|
|
415
|
-
resultPreview: normalizeText(run.resultPreview, 180) || null,
|
|
416
|
-
error: normalizeText(run.error, 160) || null,
|
|
417
|
-
})).join('\n')
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function summarizeQueuedTurns(turns: MissionPlannerInput['queuedTurns']): string {
|
|
421
|
-
if (!Array.isArray(turns) || turns.length === 0) return '(none)'
|
|
422
|
-
return turns.slice(0, 6).map((turn) => JSON.stringify({
|
|
423
|
-
runId: turn.runId,
|
|
424
|
-
source: turn.source || 'chat',
|
|
425
|
-
queuedAt: turn.queuedAt,
|
|
426
|
-
text: normalizeText(turn.text, 220) || '(empty)',
|
|
427
|
-
})).join('\n')
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
function summarizeRecentEvents(events: MissionPlannerInput['recentEvents']): string {
|
|
431
|
-
if (!Array.isArray(events) || events.length === 0) return '(none)'
|
|
432
|
-
return events.slice(-8).map((event) => JSON.stringify({
|
|
433
|
-
type: event.type,
|
|
434
|
-
summary: normalizeText(event.summary, 220),
|
|
435
|
-
createdAt: event.createdAt,
|
|
436
|
-
})).join('\n')
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
function buildMissionPlannerPrompt(input: MissionPlannerInput): string {
|
|
440
|
-
const verification = 'verificationState' in input.mission ? input.mission.verificationState : undefined
|
|
441
|
-
return [
|
|
442
|
-
'Decide the next durable mission-controller action.',
|
|
443
|
-
'Return JSON only.',
|
|
444
|
-
'',
|
|
445
|
-
'Controller rules:',
|
|
446
|
-
'- Choose exactly one decision.',
|
|
447
|
-
'- Use "dispatch_task" only when there is a specific linked backlog task to queue now. You must provide taskId.',
|
|
448
|
-
'- Use "dispatch_session_turn" when the next durable step should run as one mission-linked follow-up turn in the existing session. Provide sessionMessage.',
|
|
449
|
-
'- Use "spawn_child_mission" only when the work should split into a durable child objective with its own lifecycle.',
|
|
450
|
-
'- Use "wait" only for a real blocker, dependency, approval, human reply, provider outage, or scheduled resume. Provide waitKind and waitReason.',
|
|
451
|
-
'- Use "verify_now" when the existing durable evidence is sufficient to verify completion without more execution.',
|
|
452
|
-
'- Use "complete_candidate" only when the objective appears complete and should move into verification next.',
|
|
453
|
-
'- Use "replan" when the mission should stay active but you do not want to dispatch work from this tick. Update currentStep or summary if helpful.',
|
|
454
|
-
'- Use "fail_terminal" only for a genuine terminal failure that should stop the mission.',
|
|
455
|
-
'- Do not mark work complete based on promises, planning prose, or partial progress.',
|
|
456
|
-
'',
|
|
457
|
-
'Output shape:',
|
|
458
|
-
'{"decision":"dispatch_task|dispatch_session_turn|spawn_child_mission|wait|verify_now|complete_candidate|replan|fail_terminal","confidence":0-1,"summary":"optional","currentStep":"optional","taskId":"required for dispatch_task","sessionMessage":"required for dispatch_session_turn","waitKind":"required for wait","waitReason":"required for wait","childObjective":"required for spawn_child_mission","childSuccessCriteria":["optional"],"childCurrentStep":"optional","childPlannerSummary":"optional"}',
|
|
459
|
-
'',
|
|
460
|
-
`mission:\n${summarizeMission(input.mission)}`,
|
|
461
|
-
verification ? `verification:\n${JSON.stringify({
|
|
462
|
-
candidate: verification.candidate === true,
|
|
463
|
-
requiredTaskIds: verification.requiredTaskIds || [],
|
|
464
|
-
requiredChildMissionIds: verification.requiredChildMissionIds || [],
|
|
465
|
-
requiredArtifacts: verification.requiredArtifacts || [],
|
|
466
|
-
evidenceSummary: normalizeText(verification.evidenceSummary, 220) || null,
|
|
467
|
-
lastVerdict: verification.lastVerdict || null,
|
|
468
|
-
})}` : 'verification:\n(none)',
|
|
469
|
-
`linked_tasks:\n${summarizeLinkedTasks(input.linkedTaskSummaries)}`,
|
|
470
|
-
`child_missions:\n${summarizeChildMissions(input.childMissionSummaries)}`,
|
|
471
|
-
`recent_runs:\n${summarizeRecentRuns(input.recentRuns)}`,
|
|
472
|
-
`queued_turns:\n${summarizeQueuedTurns(input.queuedTurns)}`,
|
|
473
|
-
`recent_events:\n${summarizeRecentEvents(input.recentEvents)}`,
|
|
474
|
-
].join('\n')
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
function buildMissionTurnPrompt(input: MissionTurnClassifierInput): string {
|
|
478
|
-
return [
|
|
479
|
-
'Classify whether the latest user turn should use durable mission tracking.',
|
|
480
|
-
'Return JSON only.',
|
|
481
|
-
'',
|
|
482
|
-
'Mission policy:',
|
|
483
|
-
'- Choose "create_new" only when the request is clearly multi-step, durable, resumable, deliverable-oriented, or likely to require follow-up action.',
|
|
484
|
-
'- A small request that can be fully satisfied in the current turn should usually stay ordinary chat, even if it writes a file, produces an artifact, or could have future follow-up.',
|
|
485
|
-
'- Do not create a mission just because the user might say more later. Unspecified future instructions alone are not durable mission state.',
|
|
486
|
-
'- Choose "attach_current" when the new user turn is a continuation, refinement, correction, or next step for the current mission.',
|
|
487
|
-
'- Choose "none" for one-shot questions, casual chat, simple factual replies, or turns that should not create durable execution state.',
|
|
488
|
-
'- Be conservative. If the turn is not clearly mission-worthy, return {"action":"none","confidence":0}.',
|
|
489
|
-
'- For "create_new", provide a concise durable objective, up to 6 success criteria, and an optional currentStep/plannerSummary.',
|
|
490
|
-
'- For "attach_current", optionally provide a better currentStep/plannerSummary if the new turn changes the immediate next step.',
|
|
491
|
-
'- Never rely on literal wording like "continue" alone. Decide from intent and context.',
|
|
492
|
-
'',
|
|
493
|
-
'Output shape:',
|
|
494
|
-
'{"action":"none|attach_current|create_new","confidence":0-1,"objective":"for create_new","successCriteria":["optional"],"currentStep":"optional","plannerSummary":"optional"}',
|
|
495
|
-
'',
|
|
496
|
-
`current_mission:\n${summarizeMission(input.currentMission)}`,
|
|
497
|
-
`recent_messages:\n${buildRecentMessageContext(input.recentMessages)}`,
|
|
498
|
-
`latest_user_message: ${JSON.stringify(normalizeText(input.message, 500) || '(empty)')}`,
|
|
499
|
-
].join('\n')
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
function buildMissionOutcomePrompt(input: MissionOutcomeClassifierInput): string {
|
|
503
|
-
return [
|
|
504
|
-
'Evaluate the latest mission-scoped run outcome and decide the durable mission state.',
|
|
505
|
-
'Return JSON only.',
|
|
506
|
-
'',
|
|
507
|
-
'Rules:',
|
|
508
|
-
'- Choose "completed" only when the mission objective is actually satisfied by the latest work or the linked tasks are clearly complete.',
|
|
509
|
-
'- Choose "waiting" when progress is blocked on a real external dependency, approval, human reply, provider outage, blocked task, or scheduled future action.',
|
|
510
|
-
'- Choose "replan" when the mission should remain active but the next controller step needs to change before more work is dispatched.',
|
|
511
|
-
'- Choose "failed" only for a real terminal failure that should stop the mission instead of waiting or continuing.',
|
|
512
|
-
'- Choose "continue" for incomplete but still actionable work.',
|
|
513
|
-
'- Be conservative about completion. Planning, partial edits, vague promises, or "I will" language are not completion.',
|
|
514
|
-
'- Use the linked task summaries and tool results as stronger evidence than conversational tone.',
|
|
515
|
-
'- Provide a short verifierSummary and an optional currentStep.',
|
|
516
|
-
'',
|
|
517
|
-
'Output shape:',
|
|
518
|
-
'{"verdict":"continue|waiting|completed|failed|replan","confidence":0-1,"phase":"planning|executing|verifying|waiting|completed|failed","currentStep":"optional","verifierSummary":"optional","waitKind":"human_reply|approval|external_dependency|provider|blocked_task|blocked_mission|scheduled|other","waitReason":"optional"}',
|
|
519
|
-
'',
|
|
520
|
-
`mission:\n${summarizeMission(input.currentMission)}`,
|
|
521
|
-
`linked_tasks:\n${summarizeLinkedTasks(input.linkedTaskSummaries)}`,
|
|
522
|
-
`user_message: ${JSON.stringify(normalizeText(input.userMessage, 500) || '(empty)')}`,
|
|
523
|
-
`assistant_text: ${JSON.stringify(normalizeText(input.assistantText, 1200) || '(none)')}`,
|
|
524
|
-
`assistant_error: ${JSON.stringify(normalizeText(input.error, 320) || '(none)')}`,
|
|
525
|
-
`tool_events:\n${summarizeToolEvents(input.toolEvents)}`,
|
|
526
|
-
].join('\n')
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
async function generateClassifierText(sessionId: string, agentId: string | null | undefined, prompt: string): Promise<string> {
|
|
530
|
-
const { llm } = await buildLLM({
|
|
531
|
-
sessionId,
|
|
532
|
-
agentId: agentId || null,
|
|
533
|
-
})
|
|
534
|
-
const response = await llm.invoke([new HumanMessage(prompt)])
|
|
535
|
-
return extractModelText(response.content)
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
export async function classifyMissionTurn(
|
|
539
|
-
input: MissionTurnClassifierInput,
|
|
540
|
-
options?: { generateText?: (prompt: string) => Promise<string> },
|
|
541
|
-
): Promise<MissionTurnDecision | null> {
|
|
542
|
-
const prompt = buildMissionTurnPrompt(input)
|
|
543
|
-
const responseText = options?.generateText
|
|
544
|
-
? await options.generateText(prompt)
|
|
545
|
-
: await generateClassifierText(input.sessionId, input.agentId, prompt)
|
|
546
|
-
return parseMissionTurnDecision(responseText)
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
export async function verifyMissionOutcome(
|
|
550
|
-
input: MissionOutcomeClassifierInput,
|
|
551
|
-
options?: { generateText?: (prompt: string) => Promise<string> },
|
|
552
|
-
): Promise<MissionOutcomeDecision | null> {
|
|
553
|
-
const prompt = buildMissionOutcomePrompt(input)
|
|
554
|
-
const responseText = options?.generateText
|
|
555
|
-
? await options.generateText(prompt)
|
|
556
|
-
: await generateClassifierText(input.sessionId, input.agentId, prompt)
|
|
557
|
-
return parseMissionOutcomeDecision(responseText)
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
export async function planMissionTick(
|
|
561
|
-
input: MissionPlannerInput,
|
|
562
|
-
options?: { generateText?: (prompt: string) => Promise<string> },
|
|
563
|
-
): Promise<MissionPlannerDecisionResult | null> {
|
|
564
|
-
const prompt = buildMissionPlannerPrompt(input)
|
|
565
|
-
const responseText = options?.generateText
|
|
566
|
-
? await options.generateText(prompt)
|
|
567
|
-
: await generateClassifierText(input.sessionId, input.agentId, prompt)
|
|
568
|
-
return parseMissionPlannerDecision(responseText)
|
|
569
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import type { Mission, MissionEvent } from '@/types'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
deleteMission as deleteStoredMission,
|
|
5
|
-
loadMission as loadStoredMission,
|
|
6
|
-
loadMissionEvent as loadStoredMissionEvent,
|
|
7
|
-
loadMissionEvents as loadStoredMissionEvents,
|
|
8
|
-
loadMissions as loadStoredMissions,
|
|
9
|
-
patchMission as patchStoredMission,
|
|
10
|
-
saveMissionEvents as saveStoredMissionEvents,
|
|
11
|
-
saveMissions as saveStoredMissions,
|
|
12
|
-
upsertMission as upsertStoredMission,
|
|
13
|
-
upsertMissionEvent as upsertStoredMissionEvent,
|
|
14
|
-
upsertMissionEvents as upsertStoredMissionEvents,
|
|
15
|
-
} from '@/lib/server/storage'
|
|
16
|
-
import { createRecordRepository } from '@/lib/server/persistence/repository-utils'
|
|
17
|
-
|
|
18
|
-
export const missionRepository = createRecordRepository<Mission>(
|
|
19
|
-
'missions',
|
|
20
|
-
{
|
|
21
|
-
get(id) {
|
|
22
|
-
return loadStoredMission(id) as Mission | null
|
|
23
|
-
},
|
|
24
|
-
list() {
|
|
25
|
-
return loadStoredMissions() as Record<string, Mission>
|
|
26
|
-
},
|
|
27
|
-
upsert(id, value) {
|
|
28
|
-
upsertStoredMission(id, value as Mission)
|
|
29
|
-
},
|
|
30
|
-
replace(data) {
|
|
31
|
-
saveStoredMissions(data as Record<string, Mission>)
|
|
32
|
-
},
|
|
33
|
-
patch(id, updater) {
|
|
34
|
-
return patchStoredMission(id, updater as (current: Mission | null) => Mission | null) as Mission | null
|
|
35
|
-
},
|
|
36
|
-
delete(id) {
|
|
37
|
-
deleteStoredMission(id)
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
export const missionEventRepository = createRecordRepository<MissionEvent>(
|
|
43
|
-
'mission-events',
|
|
44
|
-
{
|
|
45
|
-
get(id) {
|
|
46
|
-
return loadStoredMissionEvent(id) as MissionEvent | null
|
|
47
|
-
},
|
|
48
|
-
list() {
|
|
49
|
-
return loadStoredMissionEvents() as Record<string, MissionEvent>
|
|
50
|
-
},
|
|
51
|
-
upsert(id, value) {
|
|
52
|
-
upsertStoredMissionEvent(id, value as MissionEvent)
|
|
53
|
-
},
|
|
54
|
-
upsertMany(entries) {
|
|
55
|
-
upsertStoredMissionEvents(entries as Array<[string, MissionEvent]>)
|
|
56
|
-
},
|
|
57
|
-
replace(data) {
|
|
58
|
-
saveStoredMissionEvents(data as Record<string, MissionEvent>)
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
export const loadMissions = () => missionRepository.list()
|
|
64
|
-
export const loadMission = (id: string) => missionRepository.get(id)
|
|
65
|
-
export const saveMissions = (items: Record<string, Mission | Record<string, unknown>>) => missionRepository.replace(items as Record<string, Mission>)
|
|
66
|
-
export const upsertMission = (id: string, value: Mission | Record<string, unknown>) => missionRepository.upsert(id, value as Mission)
|
|
67
|
-
export const patchMission = (id: string, updater: (current: Mission | null) => Mission | null) => missionRepository.patch(id, updater)
|
|
68
|
-
export const deleteMission = (id: string) => missionRepository.delete(id)
|
|
69
|
-
|
|
70
|
-
export const loadMissionEvents = () => missionEventRepository.list()
|
|
71
|
-
export const loadMissionEvent = (id: string) => missionEventRepository.get(id)
|
|
72
|
-
export const saveMissionEvents = (items: Record<string, MissionEvent | Record<string, unknown>>) => missionEventRepository.replace(items as Record<string, MissionEvent>)
|
|
73
|
-
export const upsertMissionEvent = (id: string, value: MissionEvent | Record<string, unknown>) => missionEventRepository.upsert(id, value as MissionEvent)
|
|
74
|
-
export const upsertMissionEvents = (entries: Array<[string, MissionEvent | Record<string, unknown>]>) => missionEventRepository.upsertMany(entries as Array<[string, MissionEvent]>)
|