@ziggs-ai/agent-sdk 0.1.3 → 0.1.4
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 +1 -1
- package/package.json +9 -4
- package/src/AgentHost.ts +342 -0
- package/src/adapters/OpenAIAdapter.ts +125 -0
- package/src/agent/Agent.ts +98 -0
- package/src/cognition/validateContext.ts +95 -0
- package/src/context/applyEffects.ts +80 -0
- package/src/context/batch.ts +17 -0
- package/src/context/classifyEnvelope.ts +38 -0
- package/src/context/routingLabels.ts +46 -0
- package/src/defineAgent.ts +62 -0
- package/src/formatters/AgreementFormatter.ts +111 -0
- package/src/formatters/HistoryFormatter.ts +166 -0
- package/src/formatters/index.ts +2 -0
- package/src/index.ts +86 -0
- package/src/ingress/normalizeIncoming.ts +119 -0
- package/src/memory/MemoryStore.ts +104 -0
- package/src/runtime/AgentMachine.ts +298 -0
- package/src/runtime/PromptBuilder.ts +461 -0
- package/src/runtime/buildOutcome.ts +488 -0
- package/src/runtime/defaults.ts +72 -0
- package/src/runtime/runTurn.ts +637 -0
- package/src/runtime/validateWorkflow.ts +165 -0
- package/src/server/ConnectionPool.ts +155 -0
- package/src/server/EventQueue.ts +119 -0
- package/src/server/OutboxBuffer.ts +90 -0
- package/src/server/ZiggsEffectHandler.ts +335 -0
- package/src/server/agreements/AgreementService.ts +111 -0
- package/src/server/createHealthServer.ts +8 -0
- package/src/server/proactive/ProactiveTrigger.ts +83 -0
- package/src/server/runLauncher.ts +131 -0
- package/src/server/tasks/TaskService.ts +111 -0
- package/src/server/tasks/index.ts +4 -0
- package/src/server/tasks/paymentTools.ts +156 -0
- package/src/server/tasks/protocolRunner.ts +101 -0
- package/src/server/tasks/protocolTools.ts +96 -0
- package/src/server/ziggspay/ZiggsPayClient.ts +193 -0
- package/src/shared/ids.ts +3 -0
- package/src/shared/runtimeLog.ts +72 -0
- package/src/shared/types.ts +31 -0
- package/src/tasks/protocolRegistry.ts +25 -0
- package/src/tasks/taskCore.ts +139 -0
- package/src/tools/ToolManager.ts +95 -0
- package/src/tools/{ToolProvider.js → ToolProvider.ts} +5 -15
- package/src/tools/defineTool.ts +90 -0
- package/src/tools/index.ts +5 -0
- package/src/types.ts +368 -0
- package/src/utils/jsonExtractor.ts +100 -0
- package/src/ConnectionPool.js +0 -133
- package/src/adapters/OpenAIAdapter.js +0 -73
- package/src/agent/Agent.js +0 -121
- package/src/agent/EventQueue.js +0 -68
- package/src/agent/OutboxBuffer.js +0 -62
- package/src/cognition/PromptBuilder.js +0 -312
- package/src/cognition/resolveActionTool.js +0 -12
- package/src/cognition/runTurn.js +0 -578
- package/src/context/applyEffects.js +0 -133
- package/src/context/batch.js +0 -25
- package/src/context/classifyEnvelope.js +0 -82
- package/src/context/routingLabels.js +0 -54
- package/src/createHealthServer.js +0 -28
- package/src/formatters/HistoryFormatter.js +0 -257
- package/src/formatters/TaskFormatter.js +0 -180
- package/src/formatters/index.js +0 -9
- package/src/index.js +0 -76
- package/src/ingress/normalizeIncoming.js +0 -70
- package/src/runLauncher.js +0 -159
- package/src/shared/ids.js +0 -7
- package/src/shared/types.js +0 -86
- package/src/tasks/TaskService.js +0 -247
- package/src/tasks/index.js +0 -9
- package/src/tasks/taskCore.js +0 -229
- package/src/tasks/taskProtocolRegistry.js +0 -22
- package/src/tasks/taskProtocolRunner.js +0 -107
- package/src/tasks/taskProtocolTools.js +0 -87
- package/src/tools/ToolManager.js +0 -79
- package/src/tools/defineTool.js +0 -82
- package/src/tools/index.js +0 -11
- package/src/utils/jsonExtractor.js +0 -139
- package/src/workflow/AgentMachine.js +0 -250
- package/src/workflow/WorkflowRuntime.js +0 -63
- package/src/workflow/dsl.js +0 -287
- package/src/workflow/motifs.js +0 -435
- package/src/ziggs/runtime.js +0 -192
- /package/src/adapters/{index.js → index.ts} +0 -0
package/src/tasks/TaskService.js
DELETED
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createTask as apiCreateTask,
|
|
3
|
-
updateTaskState,
|
|
4
|
-
updatePlanStep as apiUpdatePlanStep,
|
|
5
|
-
proposeToDoWork as apiProposeToDoWork,
|
|
6
|
-
delegateToAgent as apiDelegateToAgent,
|
|
7
|
-
assignTask as apiAssignTask,
|
|
8
|
-
respondToProposal as apiRespondToProposal,
|
|
9
|
-
claimLedgerTask as apiClaimLedgerTask
|
|
10
|
-
} from '@ziggs-ai/api-client';
|
|
11
|
-
|
|
12
|
-
/** @typedef {import('./taskCore.js').Task} Task */
|
|
13
|
-
/** @typedef {import('./taskCore.js').TaskWithFlags} TaskWithFlags */
|
|
14
|
-
/** @typedef {import('./taskCore.js').TaskContract} TaskContract */
|
|
15
|
-
/** @typedef {import('./taskCore.js').TaskPerspective} TaskPerspective */
|
|
16
|
-
|
|
17
|
-
function safeJsonStringify(value) {
|
|
18
|
-
if (value === null || value === undefined) return value;
|
|
19
|
-
if (typeof value === 'string') return value;
|
|
20
|
-
if (typeof value !== 'object') return String(value);
|
|
21
|
-
|
|
22
|
-
const seen = new WeakSet();
|
|
23
|
-
try {
|
|
24
|
-
return JSON.stringify(
|
|
25
|
-
value,
|
|
26
|
-
(key, val) => {
|
|
27
|
-
if (typeof val === 'object' && val !== null) {
|
|
28
|
-
if (seen.has(val)) return '[Circular]';
|
|
29
|
-
seen.add(val);
|
|
30
|
-
}
|
|
31
|
-
return val;
|
|
32
|
-
},
|
|
33
|
-
2
|
|
34
|
-
);
|
|
35
|
-
} catch {
|
|
36
|
-
return String(value);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* TaskService — thin wrapper over API client.
|
|
42
|
-
*
|
|
43
|
-
* Methods accept a single `payload` object that is forwarded to the API client
|
|
44
|
-
* with minimal mutation. The payload shape matches the backend DTOs directly
|
|
45
|
-
* so callers (taskProtocolRunner) can pass the LLM-produced args through.
|
|
46
|
-
*
|
|
47
|
-
* All methods return a {@link Task} or {@link TaskWithFlags} — the same shape
|
|
48
|
-
* the backend persists in MongoDB.
|
|
49
|
-
*/
|
|
50
|
-
export class TaskService {
|
|
51
|
-
constructor(operatorKey, agentId) {
|
|
52
|
-
if (!operatorKey) {
|
|
53
|
-
throw new Error('TaskService: operatorKey is required');
|
|
54
|
-
}
|
|
55
|
-
if (!agentId) {
|
|
56
|
-
throw new Error('TaskService: agentId is required (operator-token impersonation)');
|
|
57
|
-
}
|
|
58
|
-
this.creds = { operatorKey, agentId };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Propose work to a user or agent for approval.
|
|
63
|
-
* Creates a task in state='proposal' with proposal.status='pending'.
|
|
64
|
-
*
|
|
65
|
-
* @param {Object} payload
|
|
66
|
-
* @param {string} payload.description
|
|
67
|
-
* @param {string} payload.proposedTo - userId or agentId to approve
|
|
68
|
-
* @param {string} payload.chatId
|
|
69
|
-
* @param {TaskContract} [payload.contract]
|
|
70
|
-
* @param {TaskPerspective} [payload.perspective]
|
|
71
|
-
* @param {string} [payload.parentTaskId]
|
|
72
|
-
* @param {string} [payload.payerId]
|
|
73
|
-
* @returns {Promise<TaskWithFlags>}
|
|
74
|
-
*/
|
|
75
|
-
async proposeToDoWork(payload) {
|
|
76
|
-
try {
|
|
77
|
-
const result = await apiProposeToDoWork(payload, this.creds);
|
|
78
|
-
console.log(`✅ Proposal created (you do the work): ${result?.taskId || 'unknown'}`);
|
|
79
|
-
return result;
|
|
80
|
-
} catch (error) {
|
|
81
|
-
console.error(`❌ Proposal creation failed: ${error.message}`);
|
|
82
|
-
throw error;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Assign task directly (no proposal step). Requires parentTaskId (user approval chain).
|
|
88
|
-
* Creates a task in state='active' immediately.
|
|
89
|
-
*
|
|
90
|
-
* @param {Object} payload
|
|
91
|
-
* @param {string} payload.description
|
|
92
|
-
* @param {string} payload.executorId - agentId who will execute
|
|
93
|
-
* @param {string} payload.chatId
|
|
94
|
-
* @param {string} payload.parentTaskId - required (proves user approval)
|
|
95
|
-
* @param {TaskContract} [payload.contract]
|
|
96
|
-
* @param {TaskPerspective} [payload.perspective]
|
|
97
|
-
* @param {string} [payload.payerId]
|
|
98
|
-
* @returns {Promise<TaskWithFlags>}
|
|
99
|
-
*/
|
|
100
|
-
async assignTask(payload) {
|
|
101
|
-
try {
|
|
102
|
-
const result = await apiAssignTask(payload, this.creds);
|
|
103
|
-
console.log(`⚡ Task directly assigned (no proposal): ${result?.taskId || 'unknown'}`);
|
|
104
|
-
return result;
|
|
105
|
-
} catch (error) {
|
|
106
|
-
console.error(`❌ Task assignment failed: ${error.message}`);
|
|
107
|
-
throw error;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Delegate task to another agent (creates proposal to executor). Requires parentTaskId.
|
|
113
|
-
* Creates a task in state='proposal' where proposedTo=executorId.
|
|
114
|
-
*
|
|
115
|
-
* @param {Object} payload
|
|
116
|
-
* @param {string} payload.description
|
|
117
|
-
* @param {string} payload.executorId - agentId to delegate to
|
|
118
|
-
* @param {string} payload.chatId
|
|
119
|
-
* @param {string} payload.parentTaskId - required (proves user approval)
|
|
120
|
-
* @param {TaskContract} [payload.contract]
|
|
121
|
-
* @param {TaskPerspective} [payload.perspective]
|
|
122
|
-
* @param {string} [payload.payerId]
|
|
123
|
-
* @returns {Promise<TaskWithFlags>}
|
|
124
|
-
*/
|
|
125
|
-
async delegateToAgent(payload) {
|
|
126
|
-
try {
|
|
127
|
-
const result = await apiDelegateToAgent(payload, this.creds);
|
|
128
|
-
console.log(`✅ Proposal created (delegated): ${result?.taskId || 'unknown'}`);
|
|
129
|
-
return result;
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.error(`❌ Proposal creation failed: ${error.message}`);
|
|
132
|
-
throw error;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Create a standalone task (no proposal workflow). State starts as 'active'.
|
|
138
|
-
*
|
|
139
|
-
* @param {Object} taskData
|
|
140
|
-
* @param {string} taskData.description
|
|
141
|
-
* @param {string} [taskData.executorId]
|
|
142
|
-
* @param {string} [taskData.payerId]
|
|
143
|
-
* @param {string} [taskData.parentTaskId]
|
|
144
|
-
* @param {TaskContract} [taskData.contract]
|
|
145
|
-
* @param {TaskPerspective} [taskData.perspective]
|
|
146
|
-
* @param {{steps?: {stepId: string, description: string, order: number}[]}} [taskData.plan]
|
|
147
|
-
* @param {string} chatId
|
|
148
|
-
* @returns {Promise<Task>}
|
|
149
|
-
*/
|
|
150
|
-
async createTask(taskData, chatId) {
|
|
151
|
-
try {
|
|
152
|
-
const result = await apiCreateTask({
|
|
153
|
-
...taskData,
|
|
154
|
-
chatId
|
|
155
|
-
}, this.creds);
|
|
156
|
-
|
|
157
|
-
console.log(`✅ Task created: ${result?.taskId || 'unknown'}`);
|
|
158
|
-
return result;
|
|
159
|
-
} catch (error) {
|
|
160
|
-
console.error(`❌ Task creation failed: ${error.message}`);
|
|
161
|
-
throw error;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Respond to a proposal — approve or reject.
|
|
167
|
-
* approve: transitions state proposal→active, sets proposal.status='approved'
|
|
168
|
-
* reject: transitions state proposal→cancelled, sets proposal.status='rejected'
|
|
169
|
-
*
|
|
170
|
-
* @param {string} taskId
|
|
171
|
-
* @param {'approve'|'reject'} action
|
|
172
|
-
* @param {string} [chatId]
|
|
173
|
-
* @returns {Promise<TaskWithFlags>}
|
|
174
|
-
*/
|
|
175
|
-
async respondToProposal(taskId, action, chatId) {
|
|
176
|
-
try {
|
|
177
|
-
const result = await apiRespondToProposal(taskId, action, this.creds);
|
|
178
|
-
console.log(`✅ Proposal ${action}d: ${taskId}`);
|
|
179
|
-
return result;
|
|
180
|
-
} catch (error) {
|
|
181
|
-
console.error(`❌ Proposal response failed: ${error.message}`);
|
|
182
|
-
throw error;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Update a plan step within a task.
|
|
188
|
-
*
|
|
189
|
-
* @param {string} taskId
|
|
190
|
-
* @param {string} stepId
|
|
191
|
-
* @param {'pending'|'in_progress'|'completed'|'skipped'} status
|
|
192
|
-
* @param {*} [result]
|
|
193
|
-
* @returns {Promise<Task|null>}
|
|
194
|
-
*/
|
|
195
|
-
async updatePlanStep(taskId, stepId, status, result) {
|
|
196
|
-
try {
|
|
197
|
-
const updated = await apiUpdatePlanStep(taskId, stepId, status, result, this.creds);
|
|
198
|
-
console.log(`✅ Plan step updated: ${taskId} / ${stepId} -> ${status}`);
|
|
199
|
-
return updated;
|
|
200
|
-
} catch (error) {
|
|
201
|
-
console.error(`❌ Plan step update failed: ${error.message}`);
|
|
202
|
-
throw error;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Transition a task's state. Only valid transitions are accepted by the backend:
|
|
208
|
-
* proposal → active | cancelled
|
|
209
|
-
* active → completed | failed | cancelled
|
|
210
|
-
*
|
|
211
|
-
* @param {string} taskId
|
|
212
|
-
* @param {'completed'|'failed'|'cancelled'} status - target state
|
|
213
|
-
* @param {*} [result] - task result (stored in task.result)
|
|
214
|
-
* @param {string} [chatId]
|
|
215
|
-
* @returns {Promise<Task|null>}
|
|
216
|
-
*/
|
|
217
|
-
async updateTask(taskId, status, result, chatId) {
|
|
218
|
-
try {
|
|
219
|
-
const data = result ? { result: safeJsonStringify(result) } : {};
|
|
220
|
-
const updated = await updateTaskState(taskId, status, data, this.creds);
|
|
221
|
-
|
|
222
|
-
console.log(`✅ Task updated: ${taskId} -> ${status}`);
|
|
223
|
-
return updated;
|
|
224
|
-
} catch (error) {
|
|
225
|
-
console.error(`❌ Task update failed: ${error.message}`);
|
|
226
|
-
throw error;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Claim an open ledger task (proposal.proposedTo='everyone').
|
|
232
|
-
* Atomically sets executorId to the claiming agent and transitions to state='active'.
|
|
233
|
-
*
|
|
234
|
-
* @param {string} taskId
|
|
235
|
-
* @returns {Promise<TaskWithFlags>}
|
|
236
|
-
*/
|
|
237
|
-
async claimLedgerTask(taskId) {
|
|
238
|
-
try {
|
|
239
|
-
const task = await apiClaimLedgerTask(taskId, this.creds);
|
|
240
|
-
console.log(`✅ [ledger] Claimed task ${taskId}`);
|
|
241
|
-
return task;
|
|
242
|
-
} catch (error) {
|
|
243
|
-
console.warn(`⚠️ [ledger] Claim failed for ${taskId}: ${error.message}`);
|
|
244
|
-
throw error;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
package/src/tasks/index.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export { TaskService } from './TaskService.js';
|
|
2
|
-
export { TASK_PROTOCOL_TOOLS } from './taskProtocolTools.js';
|
|
3
|
-
export {
|
|
4
|
-
TASK_PROTOCOL_TOOL_NAMES,
|
|
5
|
-
TASK_PROTOCOL_TOOL_TO_OPERATION,
|
|
6
|
-
mapTaskProtocolToolToOperation,
|
|
7
|
-
isTaskProtocolToolName,
|
|
8
|
-
} from './taskProtocolRegistry.js';
|
|
9
|
-
export { executeTaskPayload } from './taskProtocolRunner.js';
|
package/src/tasks/taskCore.js
DELETED
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canonical Task definitions — states, state machine, shapes, and helpers.
|
|
3
|
-
*
|
|
4
|
-
* This is the single source of truth for what a Task looks like in the Ziggs system.
|
|
5
|
-
* Every layer (DB, API, SDK, frontend) must conform to these definitions.
|
|
6
|
-
*
|
|
7
|
-
* ⚠️ SYNC: Keep in sync with backend/src/tasks/task-core.ts
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
// States
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
|
|
14
|
-
export const TaskState = {
|
|
15
|
-
PROPOSAL: 'proposal',
|
|
16
|
-
ACTIVE: 'active',
|
|
17
|
-
COMPLETED: 'completed',
|
|
18
|
-
FAILED: 'failed',
|
|
19
|
-
CANCELLED: 'cancelled',
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const TASK_STATES = ['proposal', 'active', 'completed', 'failed', 'cancelled'];
|
|
23
|
-
|
|
24
|
-
export const TERMINAL_STATES = ['completed', 'failed', 'cancelled'];
|
|
25
|
-
|
|
26
|
-
// ---------------------------------------------------------------------------
|
|
27
|
-
// State Machine
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
|
|
30
|
-
export const VALID_TRANSITIONS = {
|
|
31
|
-
proposal: ['active', 'cancelled'],
|
|
32
|
-
active: ['completed', 'failed', 'cancelled'],
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export function isTerminal(state) {
|
|
36
|
-
return TERMINAL_STATES.includes(state);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function canTransitionTo(from, to) {
|
|
40
|
-
if (isTerminal(from)) return false;
|
|
41
|
-
const allowed = VALID_TRANSITIONS[from];
|
|
42
|
-
if (!allowed) return false;
|
|
43
|
-
return allowed.includes(to);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Normalize legacy state aliases.
|
|
48
|
-
* 'done' → 'completed', 'error' → 'failed'.
|
|
49
|
-
* Passthrough for canonical states.
|
|
50
|
-
*/
|
|
51
|
-
export function normalizeState(state) {
|
|
52
|
-
if (state === 'done') return TaskState.COMPLETED;
|
|
53
|
-
if (state === 'error') return TaskState.FAILED;
|
|
54
|
-
return state;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Returns true if `state` is a valid canonical TaskState value.
|
|
59
|
-
*/
|
|
60
|
-
export function isValidState(state) {
|
|
61
|
-
return TASK_STATES.includes(state);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
// Proposal
|
|
66
|
-
// ---------------------------------------------------------------------------
|
|
67
|
-
|
|
68
|
-
export const ProposalStatus = {
|
|
69
|
-
PENDING: 'pending',
|
|
70
|
-
APPROVED: 'approved',
|
|
71
|
-
REJECTED: 'rejected',
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export const OPEN_PROPOSAL_TARGET = 'everyone';
|
|
75
|
-
|
|
76
|
-
// ---------------------------------------------------------------------------
|
|
77
|
-
// Plan Step
|
|
78
|
-
// ---------------------------------------------------------------------------
|
|
79
|
-
|
|
80
|
-
export const PlanStepStatus = {
|
|
81
|
-
PENDING: 'pending',
|
|
82
|
-
IN_PROGRESS: 'in_progress',
|
|
83
|
-
COMPLETED: 'completed',
|
|
84
|
-
SKIPPED: 'skipped',
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
export const PLAN_STEP_STATUSES = ['pending', 'in_progress', 'completed', 'skipped'];
|
|
88
|
-
|
|
89
|
-
// ---------------------------------------------------------------------------
|
|
90
|
-
// History
|
|
91
|
-
// ---------------------------------------------------------------------------
|
|
92
|
-
|
|
93
|
-
export const HistoryChangeType = {
|
|
94
|
-
CREATED: 'created',
|
|
95
|
-
STATE_CHANGED: 'state_changed',
|
|
96
|
-
PROCESSING_CHANGED: 'processing_changed',
|
|
97
|
-
PROPOSAL_RESPONDED: 'proposal_responded',
|
|
98
|
-
PLAN_STEP_CHANGED: 'plan_step_changed',
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
// ---------------------------------------------------------------------------
|
|
102
|
-
// Contract lifecycle
|
|
103
|
-
// ---------------------------------------------------------------------------
|
|
104
|
-
|
|
105
|
-
export const ContractLifecycle = {
|
|
106
|
-
OPEN: 'open',
|
|
107
|
-
TIME_BOUND: 'time-bound',
|
|
108
|
-
COUNT_BOUND: 'count-bound',
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
// ---------------------------------------------------------------------------
|
|
112
|
-
// Task shape — JSDoc mirrors backend ITask interface exactly.
|
|
113
|
-
// These are not runtime constructs, just documentation so SDK devs
|
|
114
|
-
// see the same field names the backend uses.
|
|
115
|
-
// ---------------------------------------------------------------------------
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* @typedef {Object} TaskContract
|
|
119
|
-
* @property {'open'|'time-bound'|'count-bound'} lifecycle
|
|
120
|
-
* @property {string|null} expiresAt - ISO date string or null
|
|
121
|
-
* @property {number|null} maxExecutions
|
|
122
|
-
* @property {string} description
|
|
123
|
-
* @property {string} [specialistAgentId] - single specialist
|
|
124
|
-
* @property {string[]} [specialistAgentIds] - multi-specialist orchestration
|
|
125
|
-
*/
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* @typedef {Object} TaskProposal
|
|
129
|
-
* @property {string|null} proposedTo - userId/agentId or 'everyone' for ledger
|
|
130
|
-
* @property {'pending'|'approved'|'rejected'|null} status
|
|
131
|
-
* @property {string|null} respondedBy
|
|
132
|
-
* @property {string|null} proposedAt - ISO date string
|
|
133
|
-
* @property {string|null} respondedAt - ISO date string
|
|
134
|
-
*/
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* @typedef {Object} TaskPlanStep
|
|
138
|
-
* @property {string} stepId
|
|
139
|
-
* @property {string} description
|
|
140
|
-
* @property {number} order
|
|
141
|
-
* @property {'pending'|'in_progress'|'completed'|'skipped'} status
|
|
142
|
-
* @property {*} result
|
|
143
|
-
*/
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* @typedef {Object} TaskPlan
|
|
147
|
-
* @property {TaskPlanStep[]} steps
|
|
148
|
-
* @property {string} createdAt - ISO date string
|
|
149
|
-
* @property {string} updatedAt - ISO date string
|
|
150
|
-
*/
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* @typedef {Object} TaskHistoryEntry
|
|
154
|
-
* @property {'created'|'state_changed'|'processing_changed'|'proposal_responded'|'plan_step_changed'} changeType
|
|
155
|
-
* @property {*} previousState
|
|
156
|
-
* @property {*} newState
|
|
157
|
-
* @property {string} timestamp - ISO date string
|
|
158
|
-
* @property {Object} metadata
|
|
159
|
-
*/
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* @typedef {Object} TaskPerspective
|
|
163
|
-
* @property {string|null} ownerChatId
|
|
164
|
-
*/
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* The canonical Task object returned by all API endpoints.
|
|
168
|
-
* Mirrors backend ITask exactly — same fields, same names, same nesting.
|
|
169
|
-
*
|
|
170
|
-
* @typedef {Object} Task
|
|
171
|
-
* @property {string} taskId
|
|
172
|
-
* @property {string} description
|
|
173
|
-
* @property {string|null} chatId
|
|
174
|
-
* @property {string|null} agentId - who created/proposed the task
|
|
175
|
-
* @property {string|null} executorId - who executes the task
|
|
176
|
-
* @property {string|null} payerId - who pays/approves
|
|
177
|
-
* @property {TaskContract} contract
|
|
178
|
-
* @property {TaskPerspective} perspective
|
|
179
|
-
* @property {'proposal'|'active'|'completed'|'failed'|'cancelled'} state
|
|
180
|
-
* @property {TaskProposal} proposal
|
|
181
|
-
* @property {boolean} processing - atomic lock for concurrent execution
|
|
182
|
-
* @property {boolean} deleted - soft-delete flag
|
|
183
|
-
* @property {*} result
|
|
184
|
-
* @property {string|null} errorMessage
|
|
185
|
-
* @property {string} createdAt - ISO date string
|
|
186
|
-
* @property {string} updatedAt - ISO date string
|
|
187
|
-
* @property {string|null} parentTaskId
|
|
188
|
-
* @property {string|null} rootTaskId
|
|
189
|
-
* @property {TaskPlan} plan
|
|
190
|
-
* @property {TaskHistoryEntry[]} history
|
|
191
|
-
*/
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Task with "isYou" perspective flags (added by backend when requesting agent is known).
|
|
195
|
-
* Mirrors backend ITaskWithFlags.
|
|
196
|
-
*
|
|
197
|
-
* @typedef {Task & {
|
|
198
|
-
* agentIdIsYou?: boolean,
|
|
199
|
-
* executorIdIsYou?: boolean,
|
|
200
|
-
* payerIdIsYou?: boolean,
|
|
201
|
-
* proposedToIsYou?: boolean,
|
|
202
|
-
* }} TaskWithFlags
|
|
203
|
-
*/
|
|
204
|
-
|
|
205
|
-
// ---------------------------------------------------------------------------
|
|
206
|
-
// Defaults — use these when constructing task payloads to match backend defaults.
|
|
207
|
-
// ---------------------------------------------------------------------------
|
|
208
|
-
|
|
209
|
-
/** Default contract shape (matches Mongoose schema defaults). */
|
|
210
|
-
export const DEFAULT_CONTRACT = {
|
|
211
|
-
lifecycle: ContractLifecycle.OPEN,
|
|
212
|
-
expiresAt: null,
|
|
213
|
-
maxExecutions: null,
|
|
214
|
-
description: '',
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
/** Default perspective shape (matches Mongoose schema defaults). */
|
|
218
|
-
export const DEFAULT_PERSPECTIVE = {
|
|
219
|
-
ownerChatId: null,
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
/** Default proposal shape (matches Mongoose schema defaults). */
|
|
223
|
-
export const DEFAULT_PROPOSAL = {
|
|
224
|
-
proposedTo: null,
|
|
225
|
-
status: null,
|
|
226
|
-
respondedBy: null,
|
|
227
|
-
proposedAt: null,
|
|
228
|
-
respondedAt: null,
|
|
229
|
-
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Maps built-in task protocol tool names (task_*) to task service operation strings.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export const TASK_PROTOCOL_TOOL_TO_OPERATION = Object.freeze({
|
|
6
|
-
task_make_task: 'make-task',
|
|
7
|
-
task_make_sub_tasks: 'make-sub-tasks',
|
|
8
|
-
task_update_task: 'update-task',
|
|
9
|
-
task_respond_proposal: 'respond-proposal',
|
|
10
|
-
task_update_plan_step: 'update-plan-step',
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
export const TASK_PROTOCOL_TOOL_NAMES = Object.freeze(Object.keys(TASK_PROTOCOL_TOOL_TO_OPERATION));
|
|
14
|
-
|
|
15
|
-
export function mapTaskProtocolToolToOperation(toolName) {
|
|
16
|
-
if (!toolName || typeof toolName !== 'string') return null;
|
|
17
|
-
return TASK_PROTOCOL_TOOL_TO_OPERATION[toolName] || null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function isTaskProtocolToolName(toolName) {
|
|
21
|
-
return mapTaskProtocolToolToOperation(toolName) != null;
|
|
22
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared task-service execution used by the workflow engine and task protocol tools.
|
|
3
|
-
*
|
|
4
|
-
* The LLM produces a task object (e.g. { description, proposedTo, contract, ... }).
|
|
5
|
-
* This module routes it to the right TaskService method with minimal mutation —
|
|
6
|
-
* the original payload flows through to the API client almost untouched.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { normalizeState } from './taskCore.js';
|
|
10
|
-
|
|
11
|
-
function specialistIdFromTurnScratch(toolCtx) {
|
|
12
|
-
const hit = toolCtx?.turnScratch?.agentSearchLastResult;
|
|
13
|
-
if (!hit || hit.operation !== 'search' || hit.success === false) return null;
|
|
14
|
-
const outer = hit.data;
|
|
15
|
-
if (!outer || typeof outer !== 'object') return null;
|
|
16
|
-
const inner = outer.data && typeof outer.data === 'object' ? outer.data : outer;
|
|
17
|
-
const list = inner.agents;
|
|
18
|
-
if (!Array.isArray(list) || list.length === 0) return null;
|
|
19
|
-
const first = list[0];
|
|
20
|
-
const id = first?.agentId ?? first?.id;
|
|
21
|
-
return typeof id === 'string' && id.length > 0 ? id : null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export async function executeTaskPayload(taskService, task, chatId, agents = [], toolCtx = {}) {
|
|
25
|
-
if (!task?.operation) return null;
|
|
26
|
-
const { operation } = task;
|
|
27
|
-
|
|
28
|
-
switch (operation) {
|
|
29
|
-
case 'make-task':
|
|
30
|
-
return await createSingleTask(taskService, task, chatId, agents, toolCtx);
|
|
31
|
-
case 'make-sub-tasks':
|
|
32
|
-
return await createTaskWithSubtasks(taskService, task, chatId);
|
|
33
|
-
case 'update-task':
|
|
34
|
-
if (!task.taskId || !task.status) return null;
|
|
35
|
-
return await taskService.updateTask(task.taskId, normalizeState(task.status), task.result, chatId);
|
|
36
|
-
case 'respond-proposal':
|
|
37
|
-
if (!task.taskId || !task.action) return null;
|
|
38
|
-
return await taskService.respondToProposal(task.taskId, task.action, chatId);
|
|
39
|
-
case 'update-plan-step':
|
|
40
|
-
if (!task.taskId || !task.stepId || !task.status) return null;
|
|
41
|
-
return await taskService.updatePlanStep(task.taskId, task.stepId, task.status, task.result);
|
|
42
|
-
default:
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export async function createSingleTask(taskService, task, chatId, agents = [], toolCtx = {}) {
|
|
48
|
-
if (!task.description) return null;
|
|
49
|
-
|
|
50
|
-
// Build the payload from the LLM-produced fields — pass through, don't restructure.
|
|
51
|
-
// Only `operation` is SDK-internal and gets stripped.
|
|
52
|
-
const { operation: _op, ...fields } = task;
|
|
53
|
-
const inferred = specialistIdFromTurnScratch(toolCtx);
|
|
54
|
-
const mergedContract = { ...(task.contract || {}) };
|
|
55
|
-
const hasMulti =
|
|
56
|
-
Array.isArray(mergedContract.specialistAgentIds) &&
|
|
57
|
-
mergedContract.specialistAgentIds.length > 0;
|
|
58
|
-
if (!mergedContract.specialistAgentId && !hasMulti && inferred) {
|
|
59
|
-
mergedContract.specialistAgentId = inferred;
|
|
60
|
-
}
|
|
61
|
-
const payload = { ...fields, chatId, contract: mergedContract };
|
|
62
|
-
|
|
63
|
-
const parentTaskId = task.parentTaskId || null;
|
|
64
|
-
|
|
65
|
-
if (task.proposedTo && !task.executorId) {
|
|
66
|
-
const target = agents.find(a => a.agentId === task.proposedTo);
|
|
67
|
-
const caps = target?.capabilities || {};
|
|
68
|
-
// Users are never in `agents[]` as agentId — treating !target as "assign" wrongly called assignTask
|
|
69
|
-
// (requires parentTaskId) and broke user proposal cards (proposeToDoWork).
|
|
70
|
-
// Direct assign only after an approved chain: parentTaskId + (off-context executor OR tAcceptDecline false).
|
|
71
|
-
const useDirectAssign =
|
|
72
|
-
parentTaskId && (!target || caps.tAcceptDecline === false);
|
|
73
|
-
if (useDirectAssign) {
|
|
74
|
-
return await taskService.assignTask({ ...payload, executorId: task.proposedTo });
|
|
75
|
-
}
|
|
76
|
-
return await taskService.proposeToDoWork(payload);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (task.executorId) {
|
|
80
|
-
const target = agents.find(a => a.agentId === task.executorId);
|
|
81
|
-
const caps = target?.capabilities || {};
|
|
82
|
-
const useDirectAssign =
|
|
83
|
-
parentTaskId && (!target || caps.tAcceptDecline === false);
|
|
84
|
-
if (useDirectAssign) {
|
|
85
|
-
return await taskService.assignTask(payload);
|
|
86
|
-
}
|
|
87
|
-
return await taskService.delegateToAgent(payload);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return await taskService.createTask(task, chatId);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export async function createTaskWithSubtasks(taskService, task, chatId) {
|
|
94
|
-
if (!task.description || !Array.isArray(task.subtasks) || !task.subtasks.length) return null;
|
|
95
|
-
const parent = await taskService.createTask(
|
|
96
|
-
{ description: task.description, contract: task.contract || {}, perspective: task.perspective || {}, parentTaskId: task.parentTaskId || null },
|
|
97
|
-
chatId
|
|
98
|
-
);
|
|
99
|
-
if (!parent?.taskId) return null;
|
|
100
|
-
const results = await Promise.all(
|
|
101
|
-
task.subtasks.map(s => {
|
|
102
|
-
const desc = typeof s === 'string' ? s : (s.description || '');
|
|
103
|
-
return taskService.createTask({ description: desc, parentTaskId: parent.taskId }, chatId);
|
|
104
|
-
})
|
|
105
|
-
);
|
|
106
|
-
return { ...parent, subtasks: results.filter(r => r?.taskId) };
|
|
107
|
-
}
|