@ziggs-ai/agent-sdk 0.43.5 → 0.43.7
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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.43.7
|
|
6
|
+
|
|
7
|
+
- Message wakes retain the backend's authorized causal predecessors by default, so explicitly linked follow-ups can refer to earlier messages without a quoted reply in the interface. Explicit minimal reads still use only the trigger, and history never changes the selected task or agreement.
|
|
8
|
+
|
|
9
|
+
## 0.43.6
|
|
10
|
+
|
|
11
|
+
- Completing a delegated task now returns its result to the work that delegated it. A delegated result only reaches the delegator as a returned output artifact, and an agent that closed its task with `task_set_result` returned nothing, so the delegator was never woken and never saw the result. Before completing a delegated task, the SDK records the result as the task's output artifact. After completing it, the SDK returns that artifact. If either step fails, the failure is logged and the completion still stands.
|
|
12
|
+
|
|
5
13
|
## 0.43.5
|
|
6
14
|
|
|
7
15
|
- A task's input bodies (0.43.4) now actually reach a hosted workflow agent. The agent pins every context read in a wake to that wake's work, and that pin also dropped the artifact the input read named, so the read came back without a body. A read may now narrow to one artifact of the same task or agreement; any other read still gets the wake's own scope.
|
|
@@ -21,7 +21,7 @@ export const contextSnapshotTool = defineTool('context_snapshot', {
|
|
|
21
21
|
taskId: { type: 'string', description: 'Read this explicit task.' },
|
|
22
22
|
messageId: { type: 'string', description: 'Read this exact message without a saved address or work agreement.' },
|
|
23
23
|
artifactId: { type: 'string', description: 'Read this exact artifact context.' },
|
|
24
|
-
includeHistory: { type: 'boolean', description: '
|
|
24
|
+
includeHistory: { type: 'boolean', description: 'Message wakes include bounded conversation context by default. Set false to read only the trigger. Set true to include optional message history for a task or agreement without a message trigger.' },
|
|
25
25
|
maxMessages: { type: 'number', description: `Message history cap (default ${DEFAULT_SNAPSHOT_MAX_MESSAGES}). Pass a larger value when you need deeper history.` },
|
|
26
26
|
}, async (args, ctx) => {
|
|
27
27
|
const c = ctx;
|
|
@@ -44,7 +44,7 @@ export const contextSnapshotTool = defineTool('context_snapshot', {
|
|
|
44
44
|
kind: 'read-context',
|
|
45
45
|
sessionId,
|
|
46
46
|
opts: {
|
|
47
|
-
includeHistory: args.includeHistory
|
|
47
|
+
...(typeof args.includeHistory === 'boolean' ? { includeHistory: args.includeHistory } : {}),
|
|
48
48
|
maxMessages: args.maxMessages != null ? Number(args.maxMessages) : DEFAULT_SNAPSHOT_MAX_MESSAGES,
|
|
49
49
|
...(messageId || artifactId ? {
|
|
50
50
|
via: messageId ? `message:${messageId}` : `artifact:${artifactId}`,
|
|
@@ -30,7 +30,7 @@ async function buildSnapshot(deps, agentId, opts = {}) {
|
|
|
30
30
|
// Select the work independently of its triggering message. A message is
|
|
31
31
|
// the snapshot entry only when it is the selected resource itself.
|
|
32
32
|
const snap = await deps.contextReadClient.snapshot({
|
|
33
|
-
via, maxMessages: opts.limit,
|
|
33
|
+
via, maxMessages: opts.includeHistory === false && via.startsWith('message:') ? 1 : opts.limit,
|
|
34
34
|
...(agreementId ? { agreementId } : {}),
|
|
35
35
|
...(scope?.artifactId ? { artifactId: scope.artifactId } : {}),
|
|
36
36
|
});
|
|
@@ -44,10 +44,31 @@ async function buildSnapshot(deps, agentId, opts = {}) {
|
|
|
44
44
|
const present = (m) => ({ messageId: m.messageId, text: m.content.text, entryType: 'message', timestamp: Date.parse(m.timestamp), sender: { id: m.sender.isSelf ? agentId : m.sender.ref, type: m.sender.kind }, receiver: { id: m.recipients[0]?.ref } });
|
|
45
45
|
const required = trigger ? [present(trigger)] : [];
|
|
46
46
|
const context = { ...snap, messageRecord: trigger, messageMandate: agreementId ? { agreementId, ...(opts.workScope?.taskId ? { taskId: opts.workScope.taskId } : {}) } : trigger?.mandate ?? undefined };
|
|
47
|
+
if (trigger && opts.includeHistory !== false) {
|
|
48
|
+
try {
|
|
49
|
+
// An ordinary follow-up needs the preceding conversation, even when it
|
|
50
|
+
// does not explicitly quote a message. The server matches the exact
|
|
51
|
+
// stored audience and mandate and authorizes every history record.
|
|
52
|
+
// Keep selected work separate: context never selects execution authority.
|
|
53
|
+
const conversation = via === `message:${trigger.messageId}`
|
|
54
|
+
? snap
|
|
55
|
+
: await deps.contextReadClient.snapshot({ via: `message:${trigger.messageId}`, maxMessages: opts.limit ?? 12 });
|
|
56
|
+
assertRequiredContext(conversation);
|
|
57
|
+
const history = new Map(conversation.history.map(m => [m.messageId, present(m)]));
|
|
58
|
+
history.set(trigger.messageId, present(trigger));
|
|
59
|
+
return { ...context, history: [...history.values()].sort((a, b) => Number(a.timestamp) - Number(b.timestamp)) };
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
const refusal = error;
|
|
63
|
+
if (refusal.status === 401 || refusal.code?.startsWith('EXECUTION_'))
|
|
64
|
+
throw error;
|
|
65
|
+
return { ...context, history: required, historyUnavailable: true };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
47
68
|
if (trigger || agreementId) {
|
|
48
69
|
if (opts.includeHistory === true) {
|
|
49
70
|
try {
|
|
50
|
-
const page =
|
|
71
|
+
const page = await messages.list({ agreementId, taskId: opts.workScope?.taskId, limit: Math.min(opts.limit ?? 12, 30) });
|
|
51
72
|
const history = page.messages.map(present);
|
|
52
73
|
if (trigger && !page.messages.some(m => m.messageId === trigger.messageId))
|
|
53
74
|
history.unshift(present(trigger));
|
|
@@ -34,6 +34,15 @@ export declare class TaskService {
|
|
|
34
34
|
resultRecorded?: boolean;
|
|
35
35
|
terminalState?: string;
|
|
36
36
|
}>;
|
|
37
|
+
/**
|
|
38
|
+
* A delegated task's result only reaches the work that delegated it as a
|
|
39
|
+
* returned output artifact. A workflow agent closes its task with a result
|
|
40
|
+
* and nothing else, so the delegator never woke and never saw it. Before
|
|
41
|
+
* completing, record the result as this task's output; after, return it.
|
|
42
|
+
* Either step failing leaves the completion itself untouched.
|
|
43
|
+
*/
|
|
44
|
+
private delegatedOutput;
|
|
45
|
+
private returnDelegatedOutput;
|
|
37
46
|
/**
|
|
38
47
|
* Say who this task is waiting on, with no other progress to post.
|
|
39
48
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createTask, getTask, getActiveTasksForAgent, getSubtasks, updateTaskState, updateTaskPlanStep, updateTaskPlanSteps, cancelTask, reportTask, setTaskSatisfaction, countTasks, acknowledgeTaskControl, presentTaskOutcome, } from '@ziggs-ai/api-client';
|
|
1
|
+
import { createTask, getTask, getActiveTasksForAgent, getSubtasks, updateTaskState, updateTaskPlanStep, updateTaskPlanSteps, cancelTask, reportTask, setTaskSatisfaction, countTasks, acknowledgeTaskControl, presentTaskOutcome, returnTaskResult, ArtifactsClient, } from '@ziggs-ai/api-client';
|
|
2
2
|
import { runtimeLog } from '../../shared/runtimeLog.js';
|
|
3
3
|
function safeJsonStringify(value) {
|
|
4
4
|
if (value === null || value === undefined)
|
|
@@ -64,8 +64,11 @@ export class TaskService {
|
|
|
64
64
|
...(idempotencyKey ? { idempotencyKey } : {}),
|
|
65
65
|
...(sources ? { sources } : {}),
|
|
66
66
|
};
|
|
67
|
+
const output = state === 'completed' ? await this.delegatedOutput(taskId, result, idempotencyKey) : undefined;
|
|
67
68
|
const updated = await updateTaskState(taskId, state, data, this.creds);
|
|
68
69
|
runtimeLog.info('TaskService', `Task state: ${taskId} → ${state}`);
|
|
70
|
+
if (output)
|
|
71
|
+
await this.returnDelegatedOutput(taskId, output);
|
|
69
72
|
// The same four facts the MCP surface reports, from the same
|
|
70
73
|
// presenter: what was stored, who was woken, what metering did, what the
|
|
71
74
|
// agreement is now. Both surfaces say it once, and say it the same way.
|
|
@@ -79,6 +82,44 @@ export class TaskService {
|
|
|
79
82
|
throw error;
|
|
80
83
|
}
|
|
81
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* A delegated task's result only reaches the work that delegated it as a
|
|
87
|
+
* returned output artifact. A workflow agent closes its task with a result
|
|
88
|
+
* and nothing else, so the delegator never woke and never saw it. Before
|
|
89
|
+
* completing, record the result as this task's output; after, return it.
|
|
90
|
+
* Either step failing leaves the completion itself untouched.
|
|
91
|
+
*/
|
|
92
|
+
async delegatedOutput(taskId, result, idempotencyKey) {
|
|
93
|
+
try {
|
|
94
|
+
const task = await getTask(taskId, this.creds);
|
|
95
|
+
if (!task?.delegation || task.delegation.returnedArtifactId)
|
|
96
|
+
return undefined;
|
|
97
|
+
const summary = result?.summary;
|
|
98
|
+
const text = typeof summary === 'string' ? summary : safeJsonStringify(result);
|
|
99
|
+
if (!text || !String(text).trim())
|
|
100
|
+
return undefined;
|
|
101
|
+
const recorded = await new ArtifactsClient(this.creds.operatorKey, this.creds.agentId).writeStrict({
|
|
102
|
+
taskId,
|
|
103
|
+
text: String(text),
|
|
104
|
+
name: `Result of task ${taskId}`,
|
|
105
|
+
...(idempotencyKey ? { idempotencyKey: `${idempotencyKey}:output` } : {}),
|
|
106
|
+
});
|
|
107
|
+
return recorded.artifactId;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
runtimeLog.warn('TaskService', `Delegated result for ${taskId} not recorded as an output: ${error.message}`);
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async returnDelegatedOutput(taskId, artifactId) {
|
|
115
|
+
try {
|
|
116
|
+
const returned = await returnTaskResult(taskId, artifactId, this.creds);
|
|
117
|
+
runtimeLog.info('TaskService', `Delegated result returned: ${taskId} → ${returned.parentTaskId} (${artifactId}, ${returned.outcome})`);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
runtimeLog.warn('TaskService', `Delegated result for ${taskId} not returned: ${error.message}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
82
123
|
/**
|
|
83
124
|
* Say who this task is waiting on, with no other progress to post.
|
|
84
125
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/agent-sdk",
|
|
3
|
-
"version": "0.43.
|
|
3
|
+
"version": "0.43.7",
|
|
4
4
|
"description": "Agent framework SDK for building autonomous agents on the Ziggs platform",
|
|
5
5
|
"homepage": "https://ziggsai.com/docs",
|
|
6
6
|
"bugs": {
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"@anthropic-ai/claude-agent-sdk": "^0.3.284",
|
|
31
31
|
"@anthropic-ai/sdk": "^0.110.0",
|
|
32
32
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
33
|
-
"@ziggs-ai/api-client": "0.39.
|
|
34
|
-
"@ziggs-ai/contracts": "0.
|
|
33
|
+
"@ziggs-ai/api-client": "0.39.3",
|
|
34
|
+
"@ziggs-ai/contracts": "0.44.0",
|
|
35
35
|
"ajv": "^8.17.1",
|
|
36
36
|
"dotenv": "^17.2.3",
|
|
37
37
|
"openai": "^4.0.0",
|