@swarmclawai/swarmclaw 1.2.8 → 1.3.0
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 +39 -6
- package/package.json +2 -2
- package/src/app/agents/[id]/page.tsx +1 -18
- package/src/app/api/activity/route.ts +9 -23
- package/src/app/api/agents/route.ts +17 -1
- 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/approvals/route.ts +13 -5
- package/src/app/api/connectors/route.ts +2 -2
- package/src/app/api/credentials/[id]/route.ts +2 -0
- package/src/app/api/credentials/route.ts +4 -1
- package/src/app/api/goals/[id]/route.ts +28 -0
- package/src/app/api/goals/route.ts +33 -0
- 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/protocols/templates/[id]/route.ts +2 -1
- package/src/app/api/protocols/templates/route.ts +2 -1
- package/src/app/api/settings/route.ts +13 -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/home/page.tsx +3 -0
- 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 +32 -33
- package/src/cli/spec.js +26 -27
- 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/activity/activity-log.ts +16 -1
- package/src/lib/server/agents/agent-service.ts +24 -11
- 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 +14 -85
- package/src/lib/server/approvals/approval-hooks.ts +81 -0
- package/src/lib/server/approvals.test.ts +6 -6
- package/src/lib/server/approvals.ts +11 -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 +127 -0
- package/src/lib/server/connectors/swarmdock.ts +285 -0
- package/src/lib/server/execution-brief.test.ts +2 -25
- package/src/lib/server/execution-brief.ts +30 -35
- package/src/lib/server/execution-engine/task-attempt.ts +0 -1
- package/src/lib/server/goals/goal-repository.ts +19 -0
- package/src/lib/server/goals/goal-service.ts +143 -0
- 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 +13 -0
- package/src/lib/server/storage.ts +75 -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/usage/cost-rollup.ts +124 -0
- package/src/lib/server/usage/usage-repository.ts +6 -0
- 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 +36 -32
- package/src/lib/validation/server-schemas.ts +35 -0
- package/src/stores/slices/data-slice.ts +5 -1
- package/src/stores/slices/ui-slice.ts +0 -4
- package/src/types/agent.ts +10 -84
- package/src/types/app-settings.ts +6 -2
- package/src/types/approval.ts +3 -2
- package/src/types/connector.ts +1 -0
- package/src/types/goal.ts +30 -0
- package/src/types/index.ts +2 -1
- package/src/types/message.ts +0 -1
- package/src/types/misc.ts +2 -4
- 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 +9 -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
|
@@ -225,73 +225,4 @@ describe('delegation-jobs', () => {
|
|
|
225
225
|
)
|
|
226
226
|
})
|
|
227
227
|
|
|
228
|
-
it('creates and syncs a child mission for delegation jobs', async () => {
|
|
229
|
-
const storage = await import('@/lib/server/storage')
|
|
230
|
-
const missions = await import('@/lib/server/missions/mission-service')
|
|
231
|
-
|
|
232
|
-
storage.saveSessions({
|
|
233
|
-
'mission-parent-session': {
|
|
234
|
-
id: 'mission-parent-session',
|
|
235
|
-
name: 'Parent Session',
|
|
236
|
-
cwd: process.cwd(),
|
|
237
|
-
user: 'tester',
|
|
238
|
-
provider: 'ollama',
|
|
239
|
-
model: 'test-model',
|
|
240
|
-
messages: [],
|
|
241
|
-
createdAt: Date.now(),
|
|
242
|
-
lastActiveAt: Date.now(),
|
|
243
|
-
agentId: 'agent-parent',
|
|
244
|
-
},
|
|
245
|
-
})
|
|
246
|
-
storage.saveAgents({
|
|
247
|
-
'agent-parent': {
|
|
248
|
-
id: 'agent-parent',
|
|
249
|
-
name: 'Parent Agent',
|
|
250
|
-
provider: 'ollama',
|
|
251
|
-
model: 'test-model',
|
|
252
|
-
systemPrompt: 'test',
|
|
253
|
-
},
|
|
254
|
-
'agent-child': {
|
|
255
|
-
id: 'agent-child',
|
|
256
|
-
name: 'Child Agent',
|
|
257
|
-
provider: 'ollama',
|
|
258
|
-
model: 'test-model',
|
|
259
|
-
systemPrompt: 'test',
|
|
260
|
-
},
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
const parentMission = await missions.resolveMissionForTurn({
|
|
264
|
-
session: storage.loadSessions()['mission-parent-session'],
|
|
265
|
-
message: 'Build the release pipeline and delegate the test matrix.',
|
|
266
|
-
source: 'chat',
|
|
267
|
-
internal: false,
|
|
268
|
-
runId: 'run-parent',
|
|
269
|
-
generateText: async () => JSON.stringify({
|
|
270
|
-
action: 'create_new',
|
|
271
|
-
objective: 'Build the release pipeline',
|
|
272
|
-
successCriteria: ['delegated matrix completes'],
|
|
273
|
-
currentStep: 'Delegate the test matrix',
|
|
274
|
-
}),
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
const job = delegationJobs.createDelegationJob({
|
|
278
|
-
kind: 'subagent',
|
|
279
|
-
parentSessionId: 'mission-parent-session',
|
|
280
|
-
parentMissionId: parentMission?.id || null,
|
|
281
|
-
childSessionId: 'child-session-1',
|
|
282
|
-
agentId: 'agent-child',
|
|
283
|
-
task: 'Run the test matrix',
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
const started = delegationJobs.startDelegationJob(job.id, { childSessionId: 'child-session-1' })
|
|
287
|
-
const completed = delegationJobs.completeDelegationJob(job.id, 'Matrix passed')
|
|
288
|
-
const childMission = completed?.missionId ? missions.loadMissionById(completed.missionId) : null
|
|
289
|
-
const refreshedParent = parentMission?.id ? missions.loadMissionById(parentMission.id) : null
|
|
290
|
-
|
|
291
|
-
assert.ok(started?.missionId)
|
|
292
|
-
assert.equal(started?.parentMissionId, parentMission?.id || null)
|
|
293
|
-
assert.equal(childMission?.parentMissionId, parentMission?.id || null)
|
|
294
|
-
assert.equal(childMission?.status, 'completed')
|
|
295
|
-
assert.ok(refreshedParent?.childMissionIds?.includes(childMission?.id || ''))
|
|
296
|
-
})
|
|
297
228
|
})
|
|
@@ -13,8 +13,6 @@ import { log } from '@/lib/server/logger'
|
|
|
13
13
|
import { debug } from '@/lib/server/debug'
|
|
14
14
|
import { createNotification } from '@/lib/server/create-notification'
|
|
15
15
|
import { enqueueSystemEvent } from '@/lib/server/runtime/system-events'
|
|
16
|
-
import { ensureDelegationMission, syncDelegationMissionFromJob } from '@/lib/server/missions/mission-service'
|
|
17
|
-
import { loadSession } from '@/lib/server/sessions/session-repository'
|
|
18
16
|
import { notify } from '@/lib/server/ws-hub'
|
|
19
17
|
|
|
20
18
|
interface DelegationRuntimeHandle {
|
|
@@ -42,8 +40,6 @@ export interface CreateDelegationJobInput {
|
|
|
42
40
|
kind: DelegationJobRecord['kind']
|
|
43
41
|
task: string
|
|
44
42
|
backend?: DelegationJobRecord['backend']
|
|
45
|
-
missionId?: string | null
|
|
46
|
-
parentMissionId?: string | null
|
|
47
43
|
parentSessionId?: string | null
|
|
48
44
|
childSessionId?: string | null
|
|
49
45
|
agentId?: string | null
|
|
@@ -53,15 +49,11 @@ export interface CreateDelegationJobInput {
|
|
|
53
49
|
|
|
54
50
|
export function createDelegationJob(input: CreateDelegationJobInput): DelegationJobRecord {
|
|
55
51
|
const createdAt = Date.now()
|
|
56
|
-
const inferredParentMissionId = input.parentMissionId
|
|
57
|
-
|| (input.parentSessionId ? loadSession(input.parentSessionId)?.missionId || null : null)
|
|
58
52
|
const job: DelegationJobRecord = {
|
|
59
53
|
id: genId(10),
|
|
60
54
|
kind: input.kind,
|
|
61
55
|
status: 'queued',
|
|
62
56
|
backend: input.backend ?? null,
|
|
63
|
-
missionId: input.missionId ?? null,
|
|
64
|
-
parentMissionId: inferredParentMissionId,
|
|
65
57
|
parentSessionId: input.parentSessionId ?? null,
|
|
66
58
|
childSessionId: input.childSessionId ?? null,
|
|
67
59
|
agentId: input.agentId ?? null,
|
|
@@ -85,22 +77,6 @@ export function createDelegationJob(input: CreateDelegationJobInput): Delegation
|
|
|
85
77
|
completedAt: null,
|
|
86
78
|
}
|
|
87
79
|
upsertDelegationJob(job.id, job)
|
|
88
|
-
if (!job.missionId && inferredParentMissionId) {
|
|
89
|
-
const mission = ensureDelegationMission({
|
|
90
|
-
task: job.task,
|
|
91
|
-
backend: job.backend,
|
|
92
|
-
parentSessionId: job.parentSessionId || null,
|
|
93
|
-
childSessionId: job.childSessionId || null,
|
|
94
|
-
agentId: job.agentId || null,
|
|
95
|
-
parentMissionId: inferredParentMissionId,
|
|
96
|
-
jobId: job.id,
|
|
97
|
-
})
|
|
98
|
-
if (mission) {
|
|
99
|
-
job.missionId = mission.id
|
|
100
|
-
upsertDelegationJob(job.id, job)
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
syncDelegationMissionFromJob(job.id)
|
|
104
80
|
notifyDelegationJobsChanged()
|
|
105
81
|
|
|
106
82
|
const sid = job.childSessionId || job.parentSessionId || ''
|
|
@@ -151,7 +127,6 @@ export function updateDelegationJob(
|
|
|
151
127
|
}
|
|
152
128
|
})
|
|
153
129
|
if (!result) return null
|
|
154
|
-
syncDelegationMissionFromJob(id)
|
|
155
130
|
notifyDelegationJobsChanged()
|
|
156
131
|
return getDelegationJob(id) || result
|
|
157
132
|
}
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
import { loadAgents } from '@/lib/server/agents/agent-repository'
|
|
11
11
|
import { assessAutonomyRun } from '@/lib/server/autonomy/supervisor-reflection'
|
|
12
12
|
import { enqueueSystemEvent } from '@/lib/server/runtime/system-events'
|
|
13
|
-
import { buildMissionHeartbeatPrompt as buildMissionHeartbeatPromptFromMission, getMissionForSession } from '@/lib/server/missions/mission-service'
|
|
14
13
|
import { loadSettings } from '@/lib/server/settings/settings-repository'
|
|
15
14
|
import { getSession, loadSessions } from '@/lib/server/sessions/session-repository'
|
|
16
15
|
import { deleteSessionWorkingState, loadSessionWorkingState, syncWorkingStateFromMainLoopState } from '@/lib/server/working-state/service'
|
|
@@ -37,7 +36,6 @@ export interface MainLoopState {
|
|
|
37
36
|
currentPlanStep: string | null
|
|
38
37
|
reviewNote: string | null
|
|
39
38
|
reviewConfidence: number | null
|
|
40
|
-
missionTaskId: string | null
|
|
41
39
|
momentumScore: number
|
|
42
40
|
paused: boolean
|
|
43
41
|
status: 'idle' | 'progress' | 'blocked' | 'ok'
|
|
@@ -55,8 +53,6 @@ export interface MainLoopState {
|
|
|
55
53
|
note: string
|
|
56
54
|
status?: 'idle' | 'progress' | 'blocked' | 'ok' | 'reflection'
|
|
57
55
|
}>
|
|
58
|
-
missionTokens: number
|
|
59
|
-
missionCostUsd: number
|
|
60
56
|
followupChainCount: number
|
|
61
57
|
lifetimeIterations: number
|
|
62
58
|
metaMissCount: number
|
|
@@ -137,15 +133,12 @@ function defaultState(): MainLoopState {
|
|
|
137
133
|
currentPlanStep: null,
|
|
138
134
|
reviewNote: null,
|
|
139
135
|
reviewConfidence: null,
|
|
140
|
-
missionTaskId: null,
|
|
141
136
|
momentumScore: 0,
|
|
142
137
|
paused: false,
|
|
143
138
|
status: 'idle',
|
|
144
139
|
autonomyMode: 'assist',
|
|
145
140
|
pendingEvents: [],
|
|
146
141
|
timeline: [],
|
|
147
|
-
missionTokens: 0,
|
|
148
|
-
missionCostUsd: 0,
|
|
149
142
|
followupChainCount: 0,
|
|
150
143
|
lifetimeIterations: 0,
|
|
151
144
|
metaMissCount: 0,
|
|
@@ -304,8 +297,6 @@ function clampState(state: MainLoopState): MainLoopState {
|
|
|
304
297
|
state.followupChainCount = Math.max(0, Math.min(10, Math.trunc(state.followupChainCount || 0)))
|
|
305
298
|
state.lifetimeIterations = Math.max(0, Math.trunc(state.lifetimeIterations || 0))
|
|
306
299
|
state.metaMissCount = Math.max(0, Math.min(100, Math.trunc(state.metaMissCount || 0)))
|
|
307
|
-
state.missionTokens = Math.max(0, Math.trunc(state.missionTokens || 0))
|
|
308
|
-
state.missionCostUsd = Math.max(0, Number.isFinite(state.missionCostUsd) ? Number(state.missionCostUsd) : 0)
|
|
309
300
|
state.skillBlocker = normalizeSkillBlocker(state.skillBlocker)
|
|
310
301
|
state.updatedAt = typeof state.updatedAt === 'number' && Number.isFinite(state.updatedAt) ? Math.trunc(state.updatedAt) : now()
|
|
311
302
|
return state
|
|
@@ -325,15 +316,12 @@ function normalizeState(input?: Partial<MainLoopState> | null): MainLoopState {
|
|
|
325
316
|
if (typeof input.reviewConfidence === 'number' || typeof input.reviewConfidence === 'string' || input.reviewConfidence === null) {
|
|
326
317
|
next.reviewConfidence = normalizeConfidence(input.reviewConfidence)
|
|
327
318
|
}
|
|
328
|
-
if (typeof input.missionTaskId === 'string' || input.missionTaskId === null) next.missionTaskId = input.missionTaskId
|
|
329
319
|
if (typeof input.momentumScore === 'number') next.momentumScore = input.momentumScore
|
|
330
320
|
if (typeof input.paused === 'boolean') next.paused = input.paused
|
|
331
321
|
if (input.status) next.status = normalizeStatus(input.status, next.status)
|
|
332
322
|
if (input.autonomyMode) next.autonomyMode = normalizeAutonomyMode(input.autonomyMode, next.autonomyMode)
|
|
333
323
|
if (Array.isArray(input.pendingEvents)) next.pendingEvents = [...input.pendingEvents]
|
|
334
324
|
if (Array.isArray(input.timeline)) next.timeline = [...input.timeline]
|
|
335
|
-
if (typeof input.missionTokens === 'number') next.missionTokens = input.missionTokens
|
|
336
|
-
if (typeof input.missionCostUsd === 'number') next.missionCostUsd = input.missionCostUsd
|
|
337
325
|
if (typeof input.followupChainCount === 'number') next.followupChainCount = input.followupChainCount
|
|
338
326
|
if (typeof input.lifetimeIterations === 'number') next.lifetimeIterations = input.lifetimeIterations
|
|
339
327
|
if (typeof input.metaMissCount === 'number') next.metaMissCount = input.metaMissCount
|
|
@@ -435,10 +423,8 @@ function persistState(sessionId: string, state: MainLoopState): void {
|
|
|
435
423
|
upsertPersistedMainLoopState(sessionId, normalized as unknown as Record<string, unknown>)
|
|
436
424
|
const session = getSession(sessionId)
|
|
437
425
|
if (!session) return
|
|
438
|
-
const mission = getMissionForSession(session)
|
|
439
426
|
void syncWorkingStateFromMainLoopState({
|
|
440
427
|
sessionId,
|
|
441
|
-
mission,
|
|
442
428
|
goal: normalized.goal,
|
|
443
429
|
summary: normalized.summary,
|
|
444
430
|
status: normalized.status === 'ok'
|
|
@@ -797,11 +783,6 @@ export function buildMainLoopHeartbeatPrompt(session: unknown, fallbackPrompt: s
|
|
|
797
783
|
const candidate = asSession(session)
|
|
798
784
|
if (!candidate?.id) return fallbackPrompt
|
|
799
785
|
const persistedSession = getSession(String(candidate.id)) as Session | undefined
|
|
800
|
-
const missionPrompt = buildMissionHeartbeatPromptFromMission(
|
|
801
|
-
persistedSession || candidate as Session,
|
|
802
|
-
fallbackPrompt,
|
|
803
|
-
)
|
|
804
|
-
if (missionPrompt) return missionPrompt
|
|
805
786
|
const state = getOrCreateState(String(candidate.id))
|
|
806
787
|
if (!state) return fallbackPrompt
|
|
807
788
|
const latestExternalGoal = extractLatestGoal(Array.isArray(candidate.messages) ? candidate.messages as Message[] : [])
|
|
@@ -812,7 +793,6 @@ export function buildMainLoopHeartbeatPrompt(session: unknown, fallbackPrompt: s
|
|
|
812
793
|
const heartbeatSession = (persistedSession || candidate as Session)
|
|
813
794
|
const executionBrief = buildExecutionBrief({
|
|
814
795
|
session: heartbeatSession,
|
|
815
|
-
mission: getMissionForSession(heartbeatSession),
|
|
816
796
|
})
|
|
817
797
|
const executionBriefBlock = buildExecutionBriefContextBlock(executionBrief)
|
|
818
798
|
const boundedFallbackPrompt = cleanMultiline(fallbackPrompt, 500)
|
|
@@ -969,8 +949,6 @@ export function handleMainLoopRunResult(input: HandleMainLoopRunResultInput): Ma
|
|
|
969
949
|
const messageGoal = shouldCaptureMessageGoal ? parseGoalContractFromText(input.message || '') : null
|
|
970
950
|
const nowTs = now()
|
|
971
951
|
state.lifetimeIterations++
|
|
972
|
-
const mission = session ? getMissionForSession(session) : null
|
|
973
|
-
|
|
974
952
|
if (messageGoal) state.goalContract = mergeGoalContracts(state.goalContract, messageGoal)
|
|
975
953
|
if (!state.goal && shouldCaptureMessageGoal) state.goal = cleanMultiline(input.message, 900)
|
|
976
954
|
if (heartbeat?.goal) state.goal = heartbeat.goal
|
|
@@ -1011,8 +989,6 @@ export function handleMainLoopRunResult(input: HandleMainLoopRunResultInput): Ma
|
|
|
1011
989
|
|
|
1012
990
|
state.lastTickAt = nowTs
|
|
1013
991
|
state.updatedAt = nowTs
|
|
1014
|
-
state.missionTokens += Math.max(0, Math.trunc((input.inputTokens || 0) + (input.outputTokens || 0)))
|
|
1015
|
-
state.missionCostUsd += Math.max(0, Number(input.estimatedCost || 0))
|
|
1016
992
|
const cleanedResult = persistedText.trim()
|
|
1017
993
|
const waitingForExternal = extractWaitSignal(resultText)
|
|
1018
994
|
const gotTerminalAck = /^HEARTBEAT_OK$/i.test(cleanedResult) || /^NO_MESSAGE$/i.test(cleanedResult)
|
|
@@ -1073,32 +1049,8 @@ export function handleMainLoopRunResult(input: HandleMainLoopRunResultInput): Ma
|
|
|
1073
1049
|
const needsReplan = review?.needs_replan === true || ((review?.confidence ?? 1) < 0.45)
|
|
1074
1050
|
const limit = followupLimit(input.sessionId)
|
|
1075
1051
|
|
|
1076
|
-
if (mission) {
|
|
1077
|
-
state.goal = cleanMultiline(mission.objective, 900)
|
|
1078
|
-
state.missionTaskId = mission.rootTaskId || null
|
|
1079
|
-
state.summary = cleanMultiline(mission.verifierSummary || mission.plannerSummary || state.summary, 500)
|
|
1080
|
-
state.nextAction = cleanText(mission.currentStep, 280) || null
|
|
1081
|
-
state.currentPlanStep = cleanText(mission.currentStep, 280) || null
|
|
1082
|
-
state.planSteps = mission.currentStep ? [mission.currentStep] : []
|
|
1083
|
-
state.status = mission.status === 'completed'
|
|
1084
|
-
? 'ok'
|
|
1085
|
-
: mission.status === 'waiting' || mission.status === 'failed' || mission.status === 'cancelled'
|
|
1086
|
-
? 'blocked'
|
|
1087
|
-
: 'progress'
|
|
1088
|
-
state.paused = mission.status === 'waiting' || mission.status === 'failed' || mission.status === 'cancelled'
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
1052
|
let followup: MainLoopFollowupRequest | null = null
|
|
1092
|
-
if (
|
|
1093
|
-
state.followupChainCount = 0
|
|
1094
|
-
if (mission.status === 'completed') {
|
|
1095
|
-
state.status = 'ok'
|
|
1096
|
-
state.paused = false
|
|
1097
|
-
}
|
|
1098
|
-
if (mission.status === 'waiting' || mission.status === 'failed' || mission.status === 'cancelled') {
|
|
1099
|
-
state.paused = true
|
|
1100
|
-
}
|
|
1101
|
-
} else if (isDirectUserChat) {
|
|
1053
|
+
if (isDirectUserChat) {
|
|
1102
1054
|
state.followupChainCount = 0
|
|
1103
1055
|
state.lifetimeIterations = 0
|
|
1104
1056
|
if (successfulChatDelivery) {
|
|
@@ -237,7 +237,6 @@ async function spawnSubagentImpl(
|
|
|
237
237
|
const job = createDelegationJob({
|
|
238
238
|
kind: 'subagent',
|
|
239
239
|
parentSessionId: context.sessionId || null,
|
|
240
|
-
parentMissionId: typeof parent?.missionId === 'string' ? parent.missionId : null,
|
|
241
240
|
agentId: input.agentId,
|
|
242
241
|
task: input.message,
|
|
243
242
|
cwd: input.cwd || context.cwd,
|
|
@@ -34,80 +34,6 @@ function canonicalizeValue(value: unknown): unknown {
|
|
|
34
34
|
}, {})
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
function canonicalizeEthereumTransaction(value: unknown): Record<string, unknown> | null {
|
|
38
|
-
if (!isPlainRecord(value)) return null
|
|
39
|
-
const tx = value
|
|
40
|
-
const comparable: Record<string, unknown> = {}
|
|
41
|
-
const to = trimString(tx.to)
|
|
42
|
-
const data = trimString(tx.data)
|
|
43
|
-
const valueAtomic = tx.value
|
|
44
|
-
const type = normalizeScalar(tx.type)
|
|
45
|
-
const chainId = normalizeScalar(tx.chainId)
|
|
46
|
-
|
|
47
|
-
if (to) comparable.to = /^0x[0-9a-f]+$/i.test(to) ? to.toLowerCase() : to
|
|
48
|
-
if (data) comparable.data = /^0x[0-9a-f]+$/i.test(data) ? data.toLowerCase() : data
|
|
49
|
-
if (valueAtomic !== undefined && valueAtomic !== null && valueAtomic !== '') comparable.value = normalizeScalar(valueAtomic)
|
|
50
|
-
if (type !== null && type !== undefined && type !== '') comparable.type = type
|
|
51
|
-
if (chainId !== null && chainId !== undefined && chainId !== '') comparable.chainId = chainId
|
|
52
|
-
|
|
53
|
-
return Object.keys(comparable).length > 0 ? comparable : null
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function comparableWalletActionPayload(data: Record<string, unknown>): Record<string, unknown> {
|
|
57
|
-
const action = trimString(data.action)
|
|
58
|
-
const chain = trimString(data.chain)
|
|
59
|
-
const network = trimString(data.network)
|
|
60
|
-
const payload: Record<string, unknown> = {
|
|
61
|
-
action,
|
|
62
|
-
chain,
|
|
63
|
-
network,
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const transaction = canonicalizeEthereumTransaction(data.transaction)
|
|
67
|
-
if (transaction) payload.transaction = transaction
|
|
68
|
-
|
|
69
|
-
const signedTransactionFingerprint = trimString(data.signedTransactionFingerprint)
|
|
70
|
-
if (signedTransactionFingerprint) payload.signedTransactionFingerprint = signedTransactionFingerprint
|
|
71
|
-
|
|
72
|
-
const transactionFingerprint = trimString(data.transactionFingerprint)
|
|
73
|
-
if (transactionFingerprint) payload.transactionFingerprint = transactionFingerprint
|
|
74
|
-
|
|
75
|
-
const messageDigest = trimString(data.messageDigest)
|
|
76
|
-
if (messageDigest) payload.messageDigest = messageDigest
|
|
77
|
-
|
|
78
|
-
const domain = canonicalizeValue(data.domain)
|
|
79
|
-
if (domain && typeof domain === 'object') payload.domain = domain
|
|
80
|
-
|
|
81
|
-
const types = canonicalizeValue(data.types)
|
|
82
|
-
if (types && typeof types === 'object') payload.types = types
|
|
83
|
-
|
|
84
|
-
const value = canonicalizeValue(data.value)
|
|
85
|
-
if (value && typeof value === 'object') payload.value = value
|
|
86
|
-
|
|
87
|
-
const toAddress = trimString(data.toAddress)
|
|
88
|
-
if (toAddress) payload.toAddress = /^0x[0-9a-f]+$/i.test(toAddress) ? toAddress.toLowerCase() : toAddress
|
|
89
|
-
|
|
90
|
-
const amountAtomic = normalizeScalar(data.amountAtomic)
|
|
91
|
-
if (amountAtomic !== null && amountAtomic !== undefined && amountAtomic !== '') payload.amountAtomic = amountAtomic
|
|
92
|
-
|
|
93
|
-
const sellToken = trimString(data.sellToken)
|
|
94
|
-
if (sellToken) payload.sellToken = /^0x[0-9a-f]+$/i.test(sellToken) ? sellToken.toLowerCase() : sellToken
|
|
95
|
-
|
|
96
|
-
const buyToken = trimString(data.buyToken)
|
|
97
|
-
if (buyToken) payload.buyToken = /^0x[0-9a-f]+$/i.test(buyToken) ? buyToken.toLowerCase() : buyToken
|
|
98
|
-
|
|
99
|
-
const recipient = trimString(data.recipient)
|
|
100
|
-
if (recipient) payload.recipient = /^0x[0-9a-f]+$/i.test(recipient) ? recipient.toLowerCase() : recipient
|
|
101
|
-
|
|
102
|
-
const routeProvider = trimString(data.routeProvider)
|
|
103
|
-
if (routeProvider) payload.routeProvider = routeProvider
|
|
104
|
-
|
|
105
|
-
const slippageBps = normalizeScalar(data.slippageBps)
|
|
106
|
-
if (slippageBps !== null && slippageBps !== undefined && slippageBps !== '') payload.slippageBps = slippageBps
|
|
107
|
-
|
|
108
|
-
return payload
|
|
109
|
-
}
|
|
110
|
-
|
|
111
37
|
export function buildApprovalComparablePayload(
|
|
112
38
|
category: ApprovalCategory,
|
|
113
39
|
data: Record<string, unknown>,
|
|
@@ -128,17 +54,6 @@ export function buildApprovalComparablePayload(
|
|
|
128
54
|
extensionId: trimString(data.extensionId),
|
|
129
55
|
filename: trimString(data.filename),
|
|
130
56
|
}
|
|
131
|
-
case 'wallet_transfer': {
|
|
132
|
-
const toAddress = trimString(data.toAddress)
|
|
133
|
-
return {
|
|
134
|
-
chain: trimString(data.chain),
|
|
135
|
-
toAddress: /^0x[0-9a-f]+$/i.test(toAddress) ? toAddress.toLowerCase() : toAddress,
|
|
136
|
-
amountAtomic: normalizeScalar(data.amountAtomic),
|
|
137
|
-
memo: trimString(data.memo),
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
case 'wallet_action':
|
|
141
|
-
return comparableWalletActionPayload(data)
|
|
142
57
|
case 'human_loop':
|
|
143
58
|
return {
|
|
144
59
|
question: trimString(data.question),
|
|
@@ -156,6 +71,20 @@ export function buildApprovalComparablePayload(
|
|
|
156
71
|
toolName: trimString(data.toolName),
|
|
157
72
|
args: canonicalizeValue(data.args),
|
|
158
73
|
}
|
|
74
|
+
case 'agent_create':
|
|
75
|
+
return {
|
|
76
|
+
agentName: trimString(data.agentName),
|
|
77
|
+
provider: trimString(data.provider),
|
|
78
|
+
}
|
|
79
|
+
case 'budget_change':
|
|
80
|
+
return {
|
|
81
|
+
agentId: trimString(data.agentId),
|
|
82
|
+
budgetChanges: canonicalizeValue(data.budgetChanges),
|
|
83
|
+
}
|
|
84
|
+
case 'delegation_enable':
|
|
85
|
+
return {
|
|
86
|
+
agentId: trimString(data.agentId),
|
|
87
|
+
}
|
|
159
88
|
default:
|
|
160
89
|
return canonicalizeValue(data) as Record<string, unknown>
|
|
161
90
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { ApprovalRequest } from '@/types'
|
|
2
|
+
import { logActivity } from '@/lib/server/activity/activity-log'
|
|
3
|
+
import { log } from '@/lib/server/logger'
|
|
4
|
+
|
|
5
|
+
const TAG = 'approval-hooks'
|
|
6
|
+
|
|
7
|
+
type ApprovalHookHandler = (request: ApprovalRequest) => void
|
|
8
|
+
|
|
9
|
+
const approvalHandlers: Partial<Record<string, ApprovalHookHandler>> = {
|
|
10
|
+
agent_create: onAgentCreateDecided,
|
|
11
|
+
budget_change: onBudgetChangeDecided,
|
|
12
|
+
delegation_enable: onDelegationEnableDecided,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Dispatch lifecycle hooks when an approval decision is made.
|
|
17
|
+
* Called from submitDecision() after the approval is persisted.
|
|
18
|
+
*/
|
|
19
|
+
export function onApprovalDecision(request: ApprovalRequest): void {
|
|
20
|
+
const handler = approvalHandlers[request.category]
|
|
21
|
+
if (!handler) return
|
|
22
|
+
try {
|
|
23
|
+
handler(request)
|
|
24
|
+
} catch (err) {
|
|
25
|
+
log.error(TAG, `Error in approval hook for ${request.category}: ${err}`)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function onAgentCreateDecided(request: ApprovalRequest): void {
|
|
30
|
+
if (request.status !== 'approved') return
|
|
31
|
+
const pendingConfig = request.data.pendingAgentConfig as Record<string, unknown> | undefined
|
|
32
|
+
if (!pendingConfig) return
|
|
33
|
+
|
|
34
|
+
// Dynamically import to avoid circular dependency
|
|
35
|
+
import('@/lib/server/agents/agent-service').then(({ createAgent }) => {
|
|
36
|
+
const agent = createAgent({ body: pendingConfig })
|
|
37
|
+
logActivity({
|
|
38
|
+
entityType: 'agent',
|
|
39
|
+
entityId: agent.id,
|
|
40
|
+
action: 'created',
|
|
41
|
+
actor: 'system',
|
|
42
|
+
summary: `Agent "${agent.name}" created after approval ${request.id}`,
|
|
43
|
+
detail: { approvalId: request.id },
|
|
44
|
+
})
|
|
45
|
+
}).catch((err) => {
|
|
46
|
+
log.error(TAG, `Failed to create agent after approval: ${err}`)
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function onBudgetChangeDecided(request: ApprovalRequest): void {
|
|
51
|
+
if (request.status !== 'approved') return
|
|
52
|
+
const agentId = request.data.agentId as string | undefined
|
|
53
|
+
const budgetChanges = request.data.budgetChanges as Record<string, unknown> | undefined
|
|
54
|
+
if (!agentId || !budgetChanges) return
|
|
55
|
+
|
|
56
|
+
import('@/lib/server/agents/agent-service').then(({ updateAgent }) => {
|
|
57
|
+
updateAgent(agentId, budgetChanges)
|
|
58
|
+
logActivity({
|
|
59
|
+
entityType: 'budget',
|
|
60
|
+
entityId: agentId,
|
|
61
|
+
action: 'configured',
|
|
62
|
+
actor: 'system',
|
|
63
|
+
summary: `Budget updated for agent after approval ${request.id}`,
|
|
64
|
+
detail: { approvalId: request.id, budgetChanges },
|
|
65
|
+
})
|
|
66
|
+
}).catch((err) => {
|
|
67
|
+
log.error(TAG, `Failed to apply budget change after approval: ${err}`)
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function onDelegationEnableDecided(request: ApprovalRequest): void {
|
|
72
|
+
if (request.status !== 'approved') return
|
|
73
|
+
const agentId = request.data.agentId as string | undefined
|
|
74
|
+
if (!agentId) return
|
|
75
|
+
|
|
76
|
+
import('@/lib/server/agents/agent-service').then(({ updateAgent }) => {
|
|
77
|
+
updateAgent(agentId, { delegationEnabled: true })
|
|
78
|
+
}).catch((err) => {
|
|
79
|
+
log.error(TAG, `Failed to enable delegation after approval: ${err}`)
|
|
80
|
+
})
|
|
81
|
+
}
|
|
@@ -56,19 +56,19 @@ describe('approvals', () => {
|
|
|
56
56
|
title: 'Human approval',
|
|
57
57
|
data: { question: 'Proceed?' },
|
|
58
58
|
})
|
|
59
|
-
const
|
|
60
|
-
category: '
|
|
61
|
-
title: '
|
|
62
|
-
data: {
|
|
59
|
+
const other = approvals.requestApproval({
|
|
60
|
+
category: 'human_loop',
|
|
61
|
+
title: 'Another approval',
|
|
62
|
+
data: { question: 'Continue?' },
|
|
63
63
|
})
|
|
64
64
|
|
|
65
|
-
await approvals.submitDecision(
|
|
65
|
+
await approvals.submitDecision(other.id, true)
|
|
66
66
|
|
|
67
67
|
const pending = approvals.listPendingApprovals()
|
|
68
68
|
const humanPending = approvals.listPendingApprovals('human_loop')
|
|
69
69
|
|
|
70
70
|
assert.equal(pending.some((entry) => entry.id === human.id), true)
|
|
71
|
-
assert.equal(pending.some((entry) => entry.id ===
|
|
71
|
+
assert.equal(pending.some((entry) => entry.id === other.id), false)
|
|
72
72
|
assert.equal(humanPending.some((entry) => entry.id === human.id), true)
|
|
73
73
|
assert.equal(humanPending.every((entry) => entry.category === 'human_loop'), true)
|
|
74
74
|
})
|
|
@@ -5,7 +5,8 @@ import { notify } from './ws-hub'
|
|
|
5
5
|
import { dispatchWake } from '@/lib/server/runtime/wake-dispatcher'
|
|
6
6
|
import { enqueueSystemEvent } from '@/lib/server/runtime/system-events'
|
|
7
7
|
import { enqueueSessionRun } from '@/lib/server/runtime/session-run-manager'
|
|
8
|
-
import {
|
|
8
|
+
import { logActivity } from '@/lib/server/activity/activity-log'
|
|
9
|
+
import { onApprovalDecision } from '@/lib/server/approvals/approval-hooks'
|
|
9
10
|
|
|
10
11
|
function trimToString(value: unknown): string {
|
|
11
12
|
return typeof value === 'string' ? value.trim() : ''
|
|
@@ -122,11 +123,6 @@ async function persistApprovalDecision(request: ApprovalRequest, approved: boole
|
|
|
122
123
|
// best-effort trigger only
|
|
123
124
|
})
|
|
124
125
|
if (request.sessionId) notify(`session:${request.sessionId}`)
|
|
125
|
-
requestMissionTicksForApprovalDecision({
|
|
126
|
-
approvalId: request.id,
|
|
127
|
-
status: approved ? 'approved' : 'rejected',
|
|
128
|
-
sessionId: request.sessionId || null,
|
|
129
|
-
})
|
|
130
126
|
return request
|
|
131
127
|
}
|
|
132
128
|
|
|
@@ -137,6 +133,15 @@ export async function submitDecision(id: string, approved: boolean): Promise<App
|
|
|
137
133
|
if (request.status === (approved ? 'approved' : 'rejected')) return request
|
|
138
134
|
if (request.status !== 'pending') return request
|
|
139
135
|
const updated = await persistApprovalDecision(request, approved)
|
|
136
|
+
logActivity({
|
|
137
|
+
entityType: 'approval',
|
|
138
|
+
entityId: id,
|
|
139
|
+
action: approved ? 'approved' : 'rejected',
|
|
140
|
+
actor: 'user',
|
|
141
|
+
summary: `Approval ${approved ? 'approved' : 'rejected'}: ${request.title}`,
|
|
142
|
+
detail: { category: request.category, agentId: request.agentId, sessionId: request.sessionId },
|
|
143
|
+
})
|
|
144
|
+
onApprovalDecision(updated)
|
|
140
145
|
wakeForApprovalDecision(updated, approved)
|
|
141
146
|
return updated
|
|
142
147
|
}
|
|
@@ -7,10 +7,8 @@ import '@/lib/server/session-tools/memory'
|
|
|
7
7
|
import '@/lib/server/session-tools/platform'
|
|
8
8
|
import '@/lib/server/session-tools/monitor'
|
|
9
9
|
import '@/lib/server/session-tools/discovery'
|
|
10
|
-
import '@/lib/server/session-tools/wallet'
|
|
11
10
|
import '@/lib/server/session-tools/connector'
|
|
12
11
|
// http_request consolidated into web 'api' action
|
|
13
|
-
import '@/lib/server/session-tools/canvas'
|
|
14
12
|
import '@/lib/server/session-tools/chatroom'
|
|
15
13
|
import '@/lib/server/session-tools/delegate'
|
|
16
14
|
import '@/lib/server/session-tools/schedule'
|
|
@@ -80,7 +80,6 @@ test('routeTaskIntent uses structured classification when available', () => {
|
|
|
80
80
|
taskIntent: 'browsing',
|
|
81
81
|
isDeliverableTask: true,
|
|
82
82
|
isBroadGoal: false,
|
|
83
|
-
walletIntent: 'none',
|
|
84
83
|
hasHumanSignals: false,
|
|
85
84
|
hasSignificantEvent: false,
|
|
86
85
|
isResearchSynthesis: true,
|
|
@@ -108,7 +107,6 @@ function makeClassification(overrides: Partial<MessageClassification>): MessageC
|
|
|
108
107
|
taskIntent: 'general',
|
|
109
108
|
isDeliverableTask: false,
|
|
110
109
|
isBroadGoal: false,
|
|
111
|
-
walletIntent: 'none',
|
|
112
110
|
hasHumanSignals: false,
|
|
113
111
|
hasSignificantEvent: false,
|
|
114
112
|
isResearchSynthesis: false,
|
|
@@ -108,31 +108,31 @@ describe('collectToolEvent', () => {
|
|
|
108
108
|
const bag: MessageToolEvent[] = []
|
|
109
109
|
collectToolEvent({
|
|
110
110
|
t: 'tool_call',
|
|
111
|
-
toolName: '
|
|
112
|
-
toolInput: '{"
|
|
113
|
-
toolCallId: 'call-
|
|
111
|
+
toolName: 'http_request',
|
|
112
|
+
toolInput: '{"method":"GET","url":"https://api-a.example.com"}',
|
|
113
|
+
toolCallId: 'call-a',
|
|
114
114
|
}, bag)
|
|
115
115
|
collectToolEvent({
|
|
116
116
|
t: 'tool_call',
|
|
117
|
-
toolName: '
|
|
118
|
-
toolInput: '{"
|
|
119
|
-
toolCallId: 'call-
|
|
117
|
+
toolName: 'http_request',
|
|
118
|
+
toolInput: '{"method":"GET","url":"https://api-b.example.com"}',
|
|
119
|
+
toolCallId: 'call-b',
|
|
120
120
|
}, bag)
|
|
121
121
|
collectToolEvent({
|
|
122
122
|
t: 'tool_result',
|
|
123
|
-
toolName: '
|
|
124
|
-
toolOutput: '{"
|
|
125
|
-
toolCallId: 'call-
|
|
123
|
+
toolName: 'http_request',
|
|
124
|
+
toolOutput: '{"source":"api-a"}',
|
|
125
|
+
toolCallId: 'call-a',
|
|
126
126
|
}, bag)
|
|
127
127
|
collectToolEvent({
|
|
128
128
|
t: 'tool_result',
|
|
129
|
-
toolName: '
|
|
130
|
-
toolOutput: '{"
|
|
131
|
-
toolCallId: 'call-
|
|
129
|
+
toolName: 'http_request',
|
|
130
|
+
toolOutput: '{"source":"api-b"}',
|
|
131
|
+
toolCallId: 'call-b',
|
|
132
132
|
}, bag)
|
|
133
133
|
|
|
134
|
-
assert.equal(bag[0].output, '{"
|
|
135
|
-
assert.equal(bag[1].output, '{"
|
|
134
|
+
assert.equal(bag[0].output, '{"source":"api-a"}')
|
|
135
|
+
assert.equal(bag[1].output, '{"source":"api-b"}')
|
|
136
136
|
})
|
|
137
137
|
})
|
|
138
138
|
|
|
@@ -3,7 +3,6 @@ import type { MessageToolEvent, SSEEvent } from '@/types'
|
|
|
3
3
|
export interface ExecuteChatTurnInput {
|
|
4
4
|
sessionId: string
|
|
5
5
|
message: string
|
|
6
|
-
missionId?: string | null
|
|
7
6
|
imagePath?: string
|
|
8
7
|
imageUrl?: string
|
|
9
8
|
attachedFiles?: string[]
|
|
@@ -27,7 +26,6 @@ export interface ExecuteChatTurnInput {
|
|
|
27
26
|
export interface ExecuteChatTurnResult {
|
|
28
27
|
runId?: string
|
|
29
28
|
sessionId: string
|
|
30
|
-
missionId?: string | null
|
|
31
29
|
text: string
|
|
32
30
|
persisted: boolean
|
|
33
31
|
toolEvents: MessageToolEvent[]
|