@ziggs-ai/agent-sdk 0.43.4 → 0.43.6

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.6
6
+
7
+ - 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.
8
+
9
+ ## 0.43.5
10
+
11
+ - 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.
12
+
5
13
  ## 0.43.4
6
14
 
7
15
  - A workflow agent working an assigned task now sees the bodies of the task's input artifacts. The work snapshot names a task's inputs without their text, and a workflow agent has no artifact-reading tool, so a delegated task arrived with its instructions out of reach and the agent failed it. Each input (up to three) is read through the same grant-checked context read and shown in the prompt as `<task-inputs>`. An input the agent may not read is left out.
package/dist/Agent.d.ts CHANGED
@@ -522,3 +522,11 @@ export declare class Agent {
522
522
  export declare function createAgent(options?: AgentOptions | AgentConfig): Agent;
523
523
  export declare function createAgentPool(configs: AgentOptions[] | AgentConfig[]): Promise<unknown>;
524
524
  export default Agent;
525
+ type ReadScope = NonNullable<import('./types.js').ReadContextOpts['workScopes']>[number];
526
+ /**
527
+ * A read inside a wake stays on that wake's work. A caller may only narrow it
528
+ * to one artifact of the same task or agreement, which is how a task's input
529
+ * is opened with its body. Anything else reads the wake's own scopes. The
530
+ * server still checks every read.
531
+ */
532
+ export declare function readScopesForWake(asked: ReadScope[] | undefined, wake: ReadScope[]): ReadScope[];
package/dist/Agent.js CHANGED
@@ -1331,7 +1331,7 @@ export class Agent {
1331
1331
  const agreementId = marks.scope.agreementId;
1332
1332
  const sameRoom = 'sessionId' in effect && effect.sessionId === session.sessionId;
1333
1333
  const scopedEffect = sameRoom && effect.kind === 'read-context'
1334
- ? { ...effect, opts: { ...effect.opts, workScopes: contextScopesFromWake(frame, session.sessionId) } }
1334
+ ? { ...effect, opts: { ...effect.opts, workScopes: readScopesForWake(effect.opts?.workScopes, contextScopesFromWake(frame, session.sessionId)) } }
1335
1335
  : agreementId && (effect.kind === 'tool-call' || effect.kind === 'record-event')
1336
1336
  ? { ...effect, serviceAgreementId: effect.serviceAgreementId ?? agreementId }
1337
1337
  : effect;
@@ -1894,3 +1894,21 @@ export async function createAgentPool(configs) {
1894
1894
  }
1895
1895
  }
1896
1896
  export default Agent;
1897
+ /**
1898
+ * A read inside a wake stays on that wake's work. A caller may only narrow it
1899
+ * to one artifact of the same task or agreement, which is how a task's input
1900
+ * is opened with its body. Anything else reads the wake's own scopes. The
1901
+ * server still checks every read.
1902
+ */
1903
+ export function readScopesForWake(asked, wake) {
1904
+ if (!asked?.length)
1905
+ return wake;
1906
+ const narrowed = asked.map(scope => {
1907
+ if (!scope.artifactId || scope.messageId)
1908
+ return undefined;
1909
+ const base = wake.find(w => (w.taskId ?? undefined) === (scope.taskId ?? undefined)
1910
+ && (scope.agreementId ?? w.agreementId) === w.agreementId);
1911
+ return base ? { ...base, artifactId: scope.artifactId } : undefined;
1912
+ });
1913
+ return narrowed.every(Boolean) ? narrowed : wake;
1914
+ }
@@ -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.4",
3
+ "version": "0.43.6",
4
4
  "description": "Agent framework SDK for building autonomous agents on the Ziggs platform",
5
5
  "homepage": "https://ziggsai.com/docs",
6
6
  "bugs": {