@gopherhole/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 +59 -0
- package/dist/index.d.mts +15 -3
- package/dist/index.d.ts +15 -3
- package/dist/index.js +47 -2
- package/dist/index.mjs +45 -1
- package/package.json +1 -1
- package/src/index.ts +57 -2
package/README.md
CHANGED
|
@@ -48,6 +48,7 @@ new GopherHole(options: GopherHoleOptions)
|
|
|
48
48
|
- `autoReconnect` - Auto-reconnect on disconnect (default: true)
|
|
49
49
|
- `reconnectDelay` - Initial reconnect delay in ms (default: 1000)
|
|
50
50
|
- `maxReconnectAttempts` - Max reconnect attempts (default: 10)
|
|
51
|
+
- `requestTimeout` - Default HTTP request timeout in ms (default: 30000)
|
|
51
52
|
|
|
52
53
|
### Methods
|
|
53
54
|
|
|
@@ -63,6 +64,25 @@ Send a message to another agent.
|
|
|
63
64
|
#### `sendText(toAgentId: string, text: string, options?: SendOptions): Promise<Task>`
|
|
64
65
|
Send a text message to another agent.
|
|
65
66
|
|
|
67
|
+
#### `sendTextAndWait(toAgentId: string, text: string, options?: SendAndWaitOptions): Promise<Task>`
|
|
68
|
+
Send a text message and wait for the task to complete. Polls until the task reaches a terminal state.
|
|
69
|
+
|
|
70
|
+
**SendAndWaitOptions:**
|
|
71
|
+
- `timeoutMs` - Request timeout in ms (overrides default)
|
|
72
|
+
- `pollIntervalMs` - Polling interval in ms (default: 1000)
|
|
73
|
+
- `maxWaitMs` - Maximum wait time in ms (default: 300000 = 5 min)
|
|
74
|
+
|
|
75
|
+
#### `askText(toAgentId: string, text: string, options?: SendAndWaitOptions): Promise<string>`
|
|
76
|
+
Send a text message and wait for the text response. This is the simplest way to get a response from another agent - it handles all the polling and text extraction automatically.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const response = await hub.askText('weather-agent', 'What is the weather in Auckland?');
|
|
80
|
+
console.log(response); // "Currently 18°C and sunny in Auckland"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### `waitForTask(taskId: string, options?: SendAndWaitOptions): Promise<Task>`
|
|
84
|
+
Wait for an existing task to complete by polling.
|
|
85
|
+
|
|
66
86
|
#### `reply(taskId: string, payload: MessagePayload): Promise<Task>`
|
|
67
87
|
Reply to an existing conversation.
|
|
68
88
|
|
|
@@ -102,6 +122,21 @@ hub.on('error', (error) => {
|
|
|
102
122
|
});
|
|
103
123
|
```
|
|
104
124
|
|
|
125
|
+
### Helper Functions
|
|
126
|
+
|
|
127
|
+
#### `getTaskResponseText(task: Task): string`
|
|
128
|
+
Extract text response from a completed task. Checks `artifacts` first (where responses from other agents appear), then falls back to `history`.
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import { GopherHole, getTaskResponseText } from '@gopherhole/sdk';
|
|
132
|
+
|
|
133
|
+
const task = await hub.sendTextAndWait('agent-id', 'Hello!');
|
|
134
|
+
const responseText = getTaskResponseText(task);
|
|
135
|
+
console.log(responseText);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
> **Note:** Response text is typically found in `task.artifacts[].parts`, not `task.history`. Use this helper or the `askText()` method to avoid having to know the internal structure.
|
|
139
|
+
|
|
105
140
|
### Types
|
|
106
141
|
|
|
107
142
|
```typescript
|
|
@@ -142,6 +177,30 @@ interface TaskStatus {
|
|
|
142
177
|
|
|
143
178
|
## Examples
|
|
144
179
|
|
|
180
|
+
### Send and Wait for Response
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { GopherHole, getTaskResponseText } from '@gopherhole/sdk';
|
|
184
|
+
|
|
185
|
+
const hub = new GopherHole({
|
|
186
|
+
apiKey: process.env.GOPHERHOLE_API_KEY!,
|
|
187
|
+
requestTimeout: 60000, // 60s default timeout
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Option 1: Use askText() for simplest usage
|
|
191
|
+
const response = await hub.askText('weather-agent', 'What is the weather in Auckland?');
|
|
192
|
+
console.log('Response:', response);
|
|
193
|
+
|
|
194
|
+
// Option 2: Use sendTextAndWait() with helper function for more control
|
|
195
|
+
const task = await hub.sendTextAndWait('weather-agent', 'What is the weather in Auckland?', {
|
|
196
|
+
maxWaitMs: 120000, // Wait up to 2 minutes
|
|
197
|
+
pollIntervalMs: 2000, // Poll every 2 seconds
|
|
198
|
+
});
|
|
199
|
+
const responseText = getTaskResponseText(task);
|
|
200
|
+
console.log('Response:', responseText);
|
|
201
|
+
console.log('Task status:', task.status.state);
|
|
202
|
+
```
|
|
203
|
+
|
|
145
204
|
### Echo Bot
|
|
146
205
|
|
|
147
206
|
```typescript
|
package/dist/index.d.mts
CHANGED
|
@@ -243,11 +243,18 @@ interface TaskStatus {
|
|
|
243
243
|
message?: string;
|
|
244
244
|
}
|
|
245
245
|
interface Artifact {
|
|
246
|
-
name
|
|
247
|
-
|
|
246
|
+
name?: string;
|
|
247
|
+
artifactId?: string;
|
|
248
|
+
mimeType?: string;
|
|
249
|
+
parts?: MessagePart[];
|
|
248
250
|
data?: string;
|
|
249
251
|
uri?: string;
|
|
250
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* Extract text response from a completed task.
|
|
255
|
+
* Checks artifacts first (where responses live), then falls back to history.
|
|
256
|
+
*/
|
|
257
|
+
declare function getTaskResponseText(task: Task): string;
|
|
251
258
|
interface SendOptions {
|
|
252
259
|
/** Existing context/conversation ID */
|
|
253
260
|
contextId?: string;
|
|
@@ -311,6 +318,11 @@ declare class GopherHole extends EventEmitter<EventMap> {
|
|
|
311
318
|
* Returns the completed task with response artifacts
|
|
312
319
|
*/
|
|
313
320
|
sendTextAndWait(toAgentId: string, text: string, options?: SendAndWaitOptions): Promise<Task>;
|
|
321
|
+
/**
|
|
322
|
+
* Send a text message and wait for the text response
|
|
323
|
+
* This is a convenience method that extracts the response text automatically
|
|
324
|
+
*/
|
|
325
|
+
askText(toAgentId: string, text: string, options?: SendAndWaitOptions): Promise<string>;
|
|
314
326
|
/**
|
|
315
327
|
* Wait for a task to complete (polling)
|
|
316
328
|
*/
|
|
@@ -522,4 +534,4 @@ interface RatingResult {
|
|
|
522
534
|
ratingCount: number;
|
|
523
535
|
}
|
|
524
536
|
|
|
525
|
-
export { type A2AArtifact, type A2AMessage, type A2ATask, type A2ATaskStatus, type AgentAuthentication, type AgentCapabilities, type AgentCard, type AgentCardConfig, type AgentCategory, type AgentInfoResult, type AgentReview, type AgentSkill, type AgentSkillConfig, type Artifact, type ContentMode, type DataContent, type DataPart, type DiscoverOptions, type DiscoverResult, type FileContent, type FilePart, GopherHole, type GopherHoleOptions, type InputMode, type JsonRpcError, JsonRpcErrorCodes, type JsonRpcRequest, type JsonRpcResponse, type Message, type MessagePart, type MessagePayload, type MessageSendConfiguration, type OutputMode, type Part, type PublicAgent, type PushNotificationConfig, type RatingResult, type SendAndWaitOptions, type SendOptions, type Task, type TaskArtifactUpdateEvent, type TaskEvent, type TaskListConfiguration, type TaskPushNotificationConfig, type TaskQueryConfiguration, type TaskState, type TaskStatus, type TaskStatusUpdateEvent, type TextPart, GopherHole as default };
|
|
537
|
+
export { type A2AArtifact, type A2AMessage, type A2ATask, type A2ATaskStatus, type AgentAuthentication, type AgentCapabilities, type AgentCard, type AgentCardConfig, type AgentCategory, type AgentInfoResult, type AgentReview, type AgentSkill, type AgentSkillConfig, type Artifact, type ContentMode, type DataContent, type DataPart, type DiscoverOptions, type DiscoverResult, type FileContent, type FilePart, GopherHole, type GopherHoleOptions, type InputMode, type JsonRpcError, JsonRpcErrorCodes, type JsonRpcRequest, type JsonRpcResponse, type Message, type MessagePart, type MessagePayload, type MessageSendConfiguration, type OutputMode, type Part, type PublicAgent, type PushNotificationConfig, type RatingResult, type SendAndWaitOptions, type SendOptions, type Task, type TaskArtifactUpdateEvent, type TaskEvent, type TaskListConfiguration, type TaskPushNotificationConfig, type TaskQueryConfiguration, type TaskState, type TaskStatus, type TaskStatusUpdateEvent, type TextPart, GopherHole as default, getTaskResponseText };
|
package/dist/index.d.ts
CHANGED
|
@@ -243,11 +243,18 @@ interface TaskStatus {
|
|
|
243
243
|
message?: string;
|
|
244
244
|
}
|
|
245
245
|
interface Artifact {
|
|
246
|
-
name
|
|
247
|
-
|
|
246
|
+
name?: string;
|
|
247
|
+
artifactId?: string;
|
|
248
|
+
mimeType?: string;
|
|
249
|
+
parts?: MessagePart[];
|
|
248
250
|
data?: string;
|
|
249
251
|
uri?: string;
|
|
250
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* Extract text response from a completed task.
|
|
255
|
+
* Checks artifacts first (where responses live), then falls back to history.
|
|
256
|
+
*/
|
|
257
|
+
declare function getTaskResponseText(task: Task): string;
|
|
251
258
|
interface SendOptions {
|
|
252
259
|
/** Existing context/conversation ID */
|
|
253
260
|
contextId?: string;
|
|
@@ -311,6 +318,11 @@ declare class GopherHole extends EventEmitter<EventMap> {
|
|
|
311
318
|
* Returns the completed task with response artifacts
|
|
312
319
|
*/
|
|
313
320
|
sendTextAndWait(toAgentId: string, text: string, options?: SendAndWaitOptions): Promise<Task>;
|
|
321
|
+
/**
|
|
322
|
+
* Send a text message and wait for the text response
|
|
323
|
+
* This is a convenience method that extracts the response text automatically
|
|
324
|
+
*/
|
|
325
|
+
askText(toAgentId: string, text: string, options?: SendAndWaitOptions): Promise<string>;
|
|
314
326
|
/**
|
|
315
327
|
* Wait for a task to complete (polling)
|
|
316
328
|
*/
|
|
@@ -522,4 +534,4 @@ interface RatingResult {
|
|
|
522
534
|
ratingCount: number;
|
|
523
535
|
}
|
|
524
536
|
|
|
525
|
-
export { type A2AArtifact, type A2AMessage, type A2ATask, type A2ATaskStatus, type AgentAuthentication, type AgentCapabilities, type AgentCard, type AgentCardConfig, type AgentCategory, type AgentInfoResult, type AgentReview, type AgentSkill, type AgentSkillConfig, type Artifact, type ContentMode, type DataContent, type DataPart, type DiscoverOptions, type DiscoverResult, type FileContent, type FilePart, GopherHole, type GopherHoleOptions, type InputMode, type JsonRpcError, JsonRpcErrorCodes, type JsonRpcRequest, type JsonRpcResponse, type Message, type MessagePart, type MessagePayload, type MessageSendConfiguration, type OutputMode, type Part, type PublicAgent, type PushNotificationConfig, type RatingResult, type SendAndWaitOptions, type SendOptions, type Task, type TaskArtifactUpdateEvent, type TaskEvent, type TaskListConfiguration, type TaskPushNotificationConfig, type TaskQueryConfiguration, type TaskState, type TaskStatus, type TaskStatusUpdateEvent, type TextPart, GopherHole as default };
|
|
537
|
+
export { type A2AArtifact, type A2AMessage, type A2ATask, type A2ATaskStatus, type AgentAuthentication, type AgentCapabilities, type AgentCard, type AgentCardConfig, type AgentCategory, type AgentInfoResult, type AgentReview, type AgentSkill, type AgentSkillConfig, type Artifact, type ContentMode, type DataContent, type DataPart, type DiscoverOptions, type DiscoverResult, type FileContent, type FilePart, GopherHole, type GopherHoleOptions, type InputMode, type JsonRpcError, JsonRpcErrorCodes, type JsonRpcRequest, type JsonRpcResponse, type Message, type MessagePart, type MessagePayload, type MessageSendConfiguration, type OutputMode, type Part, type PublicAgent, type PushNotificationConfig, type RatingResult, type SendAndWaitOptions, type SendOptions, type Task, type TaskArtifactUpdateEvent, type TaskEvent, type TaskListConfiguration, type TaskPushNotificationConfig, type TaskQueryConfiguration, type TaskState, type TaskStatus, type TaskStatusUpdateEvent, type TextPart, GopherHole as default, getTaskResponseText };
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,8 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
GopherHole: () => GopherHole,
|
|
24
24
|
JsonRpcErrorCodes: () => JsonRpcErrorCodes,
|
|
25
|
-
default: () => index_default
|
|
25
|
+
default: () => index_default,
|
|
26
|
+
getTaskResponseText: () => getTaskResponseText
|
|
26
27
|
});
|
|
27
28
|
module.exports = __toCommonJS(index_exports);
|
|
28
29
|
var import_eventemitter3 = require("eventemitter3");
|
|
@@ -44,6 +45,38 @@ var JsonRpcErrorCodes = {
|
|
|
44
45
|
};
|
|
45
46
|
|
|
46
47
|
// src/index.ts
|
|
48
|
+
function getTaskResponseText(task) {
|
|
49
|
+
if (task.artifacts?.length) {
|
|
50
|
+
const texts = [];
|
|
51
|
+
for (const artifact of task.artifacts) {
|
|
52
|
+
if (artifact.parts) {
|
|
53
|
+
for (const part of artifact.parts) {
|
|
54
|
+
if (part.kind === "text" && part.text) {
|
|
55
|
+
texts.push(part.text);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (texts.length > 0) {
|
|
61
|
+
return texts.join("\n");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (task.history?.length) {
|
|
65
|
+
const lastMessage = task.history[task.history.length - 1];
|
|
66
|
+
if (lastMessage.parts) {
|
|
67
|
+
const texts = [];
|
|
68
|
+
for (const part of lastMessage.parts) {
|
|
69
|
+
if (part.kind === "text" && part.text) {
|
|
70
|
+
texts.push(part.text);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (texts.length > 0) {
|
|
74
|
+
return texts.join("\n");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return "";
|
|
79
|
+
}
|
|
47
80
|
var DEFAULT_HUB_URL = "wss://gopherhole.helixdata.workers.dev/ws";
|
|
48
81
|
var GopherHole = class extends import_eventemitter3.EventEmitter {
|
|
49
82
|
constructor(apiKeyOrOptions) {
|
|
@@ -160,6 +193,17 @@ var GopherHole = class extends import_eventemitter3.EventEmitter {
|
|
|
160
193
|
const task = await this.sendText(toAgentId, text, options);
|
|
161
194
|
return this.waitForTask(task.id, options);
|
|
162
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Send a text message and wait for the text response
|
|
198
|
+
* This is a convenience method that extracts the response text automatically
|
|
199
|
+
*/
|
|
200
|
+
async askText(toAgentId, text, options) {
|
|
201
|
+
const task = await this.sendTextAndWait(toAgentId, text, options);
|
|
202
|
+
if (task.status.state === "failed") {
|
|
203
|
+
throw new Error(task.status.message || "Task failed");
|
|
204
|
+
}
|
|
205
|
+
return getTaskResponseText(task);
|
|
206
|
+
}
|
|
163
207
|
/**
|
|
164
208
|
* Wait for a task to complete (polling)
|
|
165
209
|
*/
|
|
@@ -494,5 +538,6 @@ var index_default = GopherHole;
|
|
|
494
538
|
// Annotate the CommonJS export names for ESM import in node:
|
|
495
539
|
0 && (module.exports = {
|
|
496
540
|
GopherHole,
|
|
497
|
-
JsonRpcErrorCodes
|
|
541
|
+
JsonRpcErrorCodes,
|
|
542
|
+
getTaskResponseText
|
|
498
543
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -25,6 +25,38 @@ var JsonRpcErrorCodes = {
|
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
// src/index.ts
|
|
28
|
+
function getTaskResponseText(task) {
|
|
29
|
+
if (task.artifacts?.length) {
|
|
30
|
+
const texts = [];
|
|
31
|
+
for (const artifact of task.artifacts) {
|
|
32
|
+
if (artifact.parts) {
|
|
33
|
+
for (const part of artifact.parts) {
|
|
34
|
+
if (part.kind === "text" && part.text) {
|
|
35
|
+
texts.push(part.text);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (texts.length > 0) {
|
|
41
|
+
return texts.join("\n");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (task.history?.length) {
|
|
45
|
+
const lastMessage = task.history[task.history.length - 1];
|
|
46
|
+
if (lastMessage.parts) {
|
|
47
|
+
const texts = [];
|
|
48
|
+
for (const part of lastMessage.parts) {
|
|
49
|
+
if (part.kind === "text" && part.text) {
|
|
50
|
+
texts.push(part.text);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (texts.length > 0) {
|
|
54
|
+
return texts.join("\n");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return "";
|
|
59
|
+
}
|
|
28
60
|
var DEFAULT_HUB_URL = "wss://gopherhole.helixdata.workers.dev/ws";
|
|
29
61
|
var GopherHole = class extends EventEmitter {
|
|
30
62
|
constructor(apiKeyOrOptions) {
|
|
@@ -141,6 +173,17 @@ var GopherHole = class extends EventEmitter {
|
|
|
141
173
|
const task = await this.sendText(toAgentId, text, options);
|
|
142
174
|
return this.waitForTask(task.id, options);
|
|
143
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Send a text message and wait for the text response
|
|
178
|
+
* This is a convenience method that extracts the response text automatically
|
|
179
|
+
*/
|
|
180
|
+
async askText(toAgentId, text, options) {
|
|
181
|
+
const task = await this.sendTextAndWait(toAgentId, text, options);
|
|
182
|
+
if (task.status.state === "failed") {
|
|
183
|
+
throw new Error(task.status.message || "Task failed");
|
|
184
|
+
}
|
|
185
|
+
return getTaskResponseText(task);
|
|
186
|
+
}
|
|
144
187
|
/**
|
|
145
188
|
* Wait for a task to complete (polling)
|
|
146
189
|
*/
|
|
@@ -475,5 +518,6 @@ var index_default = GopherHole;
|
|
|
475
518
|
export {
|
|
476
519
|
GopherHole,
|
|
477
520
|
JsonRpcErrorCodes,
|
|
478
|
-
index_default as default
|
|
521
|
+
index_default as default,
|
|
522
|
+
getTaskResponseText
|
|
479
523
|
};
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -75,12 +75,55 @@ export interface TaskStatus {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export interface Artifact {
|
|
78
|
-
name
|
|
79
|
-
|
|
78
|
+
name?: string;
|
|
79
|
+
artifactId?: string;
|
|
80
|
+
mimeType?: string;
|
|
81
|
+
parts?: MessagePart[];
|
|
80
82
|
data?: string;
|
|
81
83
|
uri?: string;
|
|
82
84
|
}
|
|
83
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Extract text response from a completed task.
|
|
88
|
+
* Checks artifacts first (where responses live), then falls back to history.
|
|
89
|
+
*/
|
|
90
|
+
export function getTaskResponseText(task: Task): string {
|
|
91
|
+
// Check artifacts first (this is where responses from other agents appear)
|
|
92
|
+
if (task.artifacts?.length) {
|
|
93
|
+
const texts: string[] = [];
|
|
94
|
+
for (const artifact of task.artifacts) {
|
|
95
|
+
if (artifact.parts) {
|
|
96
|
+
for (const part of artifact.parts) {
|
|
97
|
+
if (part.kind === 'text' && part.text) {
|
|
98
|
+
texts.push(part.text);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (texts.length > 0) {
|
|
104
|
+
return texts.join('\n');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Fall back to history (last message)
|
|
109
|
+
if (task.history?.length) {
|
|
110
|
+
const lastMessage = task.history[task.history.length - 1];
|
|
111
|
+
if (lastMessage.parts) {
|
|
112
|
+
const texts: string[] = [];
|
|
113
|
+
for (const part of lastMessage.parts) {
|
|
114
|
+
if (part.kind === 'text' && part.text) {
|
|
115
|
+
texts.push(part.text);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (texts.length > 0) {
|
|
119
|
+
return texts.join('\n');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return '';
|
|
125
|
+
}
|
|
126
|
+
|
|
84
127
|
export interface SendOptions {
|
|
85
128
|
/** Existing context/conversation ID */
|
|
86
129
|
contextId?: string;
|
|
@@ -253,6 +296,18 @@ export class GopherHole extends EventEmitter<EventMap> {
|
|
|
253
296
|
return this.waitForTask(task.id, options);
|
|
254
297
|
}
|
|
255
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Send a text message and wait for the text response
|
|
301
|
+
* This is a convenience method that extracts the response text automatically
|
|
302
|
+
*/
|
|
303
|
+
async askText(toAgentId: string, text: string, options?: SendAndWaitOptions): Promise<string> {
|
|
304
|
+
const task = await this.sendTextAndWait(toAgentId, text, options);
|
|
305
|
+
if (task.status.state === 'failed') {
|
|
306
|
+
throw new Error(task.status.message || 'Task failed');
|
|
307
|
+
}
|
|
308
|
+
return getTaskResponseText(task);
|
|
309
|
+
}
|
|
310
|
+
|
|
256
311
|
/**
|
|
257
312
|
* Wait for a task to complete (polling)
|
|
258
313
|
*/
|