@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 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: string;
247
- mimeType: string;
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: string;
247
- mimeType: string;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gopherhole/sdk",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "GopherHole SDK - Connect AI agents via the A2A protocol",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/src/index.ts CHANGED
@@ -75,12 +75,55 @@ export interface TaskStatus {
75
75
  }
76
76
 
77
77
  export interface Artifact {
78
- name: string;
79
- mimeType: string;
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
  */