@gopherhole/sdk 0.1.0 ā 0.1.1
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 +140 -73
- package/dist/index.d.mts +499 -0
- package/dist/index.d.ts +472 -40
- package/dist/index.js +442 -197
- package/dist/index.mjs +433 -0
- package/package.json +39 -7
- package/src/index.ts +607 -204
- package/src/types.ts +232 -0
- package/tsconfig.json +9 -6
- package/listen-marketclaw.ts +0 -26
- package/send-from-nova.ts +0 -28
- package/test.ts +0 -86
package/src/types.ts
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A Protocol Types
|
|
3
|
+
* Based on Google's Agent-to-Agent Protocol specification
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// ============ Core Types ============
|
|
7
|
+
|
|
8
|
+
export interface AgentCard {
|
|
9
|
+
name: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
url: string;
|
|
12
|
+
provider?: {
|
|
13
|
+
organization: string;
|
|
14
|
+
url?: string;
|
|
15
|
+
};
|
|
16
|
+
version: string;
|
|
17
|
+
documentationUrl?: string;
|
|
18
|
+
capabilities: AgentCapabilities;
|
|
19
|
+
authentication?: AgentAuthentication;
|
|
20
|
+
defaultInputModes?: InputMode[];
|
|
21
|
+
defaultOutputModes?: OutputMode[];
|
|
22
|
+
skills?: AgentSkill[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface AgentCapabilities {
|
|
26
|
+
streaming?: boolean;
|
|
27
|
+
pushNotifications?: boolean;
|
|
28
|
+
stateTransitionHistory?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface AgentAuthentication {
|
|
32
|
+
schemes: string[];
|
|
33
|
+
credentials?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface AgentSkill {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
description?: string;
|
|
40
|
+
tags?: string[];
|
|
41
|
+
examples?: string[];
|
|
42
|
+
inputModes?: ContentMode[];
|
|
43
|
+
outputModes?: ContentMode[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Content mode - MIME type string or legacy shorthand
|
|
48
|
+
* Examples: 'text/plain', 'text/markdown', 'application/json', 'image/png'
|
|
49
|
+
* Legacy: 'text', 'file', 'data' (still supported for backwards compat)
|
|
50
|
+
*/
|
|
51
|
+
export type ContentMode = string;
|
|
52
|
+
|
|
53
|
+
// Legacy type aliases for backwards compatibility
|
|
54
|
+
export type InputMode = ContentMode;
|
|
55
|
+
export type OutputMode = ContentMode;
|
|
56
|
+
|
|
57
|
+
// ============ Message Types ============
|
|
58
|
+
|
|
59
|
+
export interface A2AMessage {
|
|
60
|
+
role: 'user' | 'agent';
|
|
61
|
+
parts: Part[];
|
|
62
|
+
metadata?: Record<string, unknown>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export type Part = TextPart | FilePart | DataPart;
|
|
66
|
+
|
|
67
|
+
export interface TextPart {
|
|
68
|
+
kind: 'text';
|
|
69
|
+
text: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface FilePart {
|
|
73
|
+
kind: 'file';
|
|
74
|
+
file: FileContent;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface DataPart {
|
|
78
|
+
kind: 'data';
|
|
79
|
+
data: DataContent;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface FileContent {
|
|
83
|
+
name?: string;
|
|
84
|
+
mimeType?: string;
|
|
85
|
+
bytes?: string; // base64
|
|
86
|
+
uri?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface DataContent {
|
|
90
|
+
mimeType: string;
|
|
91
|
+
data: string; // JSON string
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ============ Task Types ============
|
|
95
|
+
|
|
96
|
+
export interface A2ATask {
|
|
97
|
+
id: string;
|
|
98
|
+
contextId: string;
|
|
99
|
+
status: A2ATaskStatus;
|
|
100
|
+
history?: A2AMessage[];
|
|
101
|
+
artifacts?: A2AArtifact[];
|
|
102
|
+
metadata?: Record<string, unknown>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface A2ATaskStatus {
|
|
106
|
+
state: TaskState;
|
|
107
|
+
timestamp: string;
|
|
108
|
+
message?: A2AMessage;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export type TaskState =
|
|
112
|
+
| 'submitted'
|
|
113
|
+
| 'working'
|
|
114
|
+
| 'input-required'
|
|
115
|
+
| 'completed'
|
|
116
|
+
| 'failed'
|
|
117
|
+
| 'canceled'
|
|
118
|
+
| 'rejected'
|
|
119
|
+
| 'auth-required';
|
|
120
|
+
|
|
121
|
+
export interface A2AArtifact {
|
|
122
|
+
name?: string;
|
|
123
|
+
description?: string;
|
|
124
|
+
parts: Part[];
|
|
125
|
+
index?: number;
|
|
126
|
+
append?: boolean;
|
|
127
|
+
lastChunk?: boolean;
|
|
128
|
+
metadata?: Record<string, unknown>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ============ JSON-RPC Types ============
|
|
132
|
+
|
|
133
|
+
export interface JsonRpcRequest {
|
|
134
|
+
jsonrpc: '2.0';
|
|
135
|
+
method: string;
|
|
136
|
+
params?: Record<string, unknown>;
|
|
137
|
+
id: string | number;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface JsonRpcResponse<T = unknown> {
|
|
141
|
+
jsonrpc: '2.0';
|
|
142
|
+
result?: T;
|
|
143
|
+
error?: JsonRpcError;
|
|
144
|
+
id: string | number;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface JsonRpcError {
|
|
148
|
+
code: number;
|
|
149
|
+
message: string;
|
|
150
|
+
data?: unknown;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Standard JSON-RPC error codes
|
|
154
|
+
export const JsonRpcErrorCodes = {
|
|
155
|
+
ParseError: -32700,
|
|
156
|
+
InvalidRequest: -32600,
|
|
157
|
+
MethodNotFound: -32601,
|
|
158
|
+
InvalidParams: -32602,
|
|
159
|
+
InternalError: -32603,
|
|
160
|
+
// A2A-specific errors
|
|
161
|
+
TaskNotFound: -32001,
|
|
162
|
+
TaskNotCancelable: -32002,
|
|
163
|
+
PushNotificationNotSupported: -32003,
|
|
164
|
+
UnsupportedOperation: -32004,
|
|
165
|
+
ContentTypeNotSupported: -32005,
|
|
166
|
+
InvalidAgentCard: -32006,
|
|
167
|
+
} as const;
|
|
168
|
+
|
|
169
|
+
// ============ Push Notification Types ============
|
|
170
|
+
|
|
171
|
+
export interface PushNotificationConfig {
|
|
172
|
+
url: string;
|
|
173
|
+
token?: string;
|
|
174
|
+
authentication?: {
|
|
175
|
+
scheme: string;
|
|
176
|
+
credentials?: string;
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export interface TaskPushNotificationConfig {
|
|
181
|
+
id: string;
|
|
182
|
+
taskId: string;
|
|
183
|
+
url: string;
|
|
184
|
+
token?: string;
|
|
185
|
+
authentication?: {
|
|
186
|
+
scheme: string;
|
|
187
|
+
credentials?: string;
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ============ Configuration Types ============
|
|
192
|
+
|
|
193
|
+
export interface MessageSendConfiguration {
|
|
194
|
+
agentId?: string;
|
|
195
|
+
contextId?: string;
|
|
196
|
+
historyLength?: number;
|
|
197
|
+
pushNotificationConfig?: PushNotificationConfig;
|
|
198
|
+
blocking?: boolean;
|
|
199
|
+
acceptedOutputModes?: OutputMode[];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface TaskQueryConfiguration {
|
|
203
|
+
id: string;
|
|
204
|
+
historyLength?: number;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface TaskListConfiguration {
|
|
208
|
+
contextId?: string;
|
|
209
|
+
pageSize?: number;
|
|
210
|
+
pageToken?: string;
|
|
211
|
+
sortOrder?: 'asc' | 'desc';
|
|
212
|
+
includeArtifacts?: boolean;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ============ Event Types ============
|
|
216
|
+
|
|
217
|
+
export interface TaskStatusUpdateEvent {
|
|
218
|
+
type: 'status';
|
|
219
|
+
taskId: string;
|
|
220
|
+
contextId: string;
|
|
221
|
+
status: A2ATaskStatus;
|
|
222
|
+
final: boolean;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export interface TaskArtifactUpdateEvent {
|
|
226
|
+
type: 'artifact';
|
|
227
|
+
taskId: string;
|
|
228
|
+
contextId: string;
|
|
229
|
+
artifact: A2AArtifact;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export type TaskEvent = TaskStatusUpdateEvent | TaskArtifactUpdateEvent;
|
package/tsconfig.json
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"target": "
|
|
3
|
+
"target": "ES2020",
|
|
4
4
|
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
6
|
"declaration": true,
|
|
7
|
-
"
|
|
8
|
-
"rootDir": "src",
|
|
7
|
+
"declarationMap": true,
|
|
9
8
|
"strict": true,
|
|
10
9
|
"esModuleInterop": true,
|
|
11
|
-
"skipLibCheck": true
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"outDir": "dist",
|
|
13
|
+
"rootDir": "src"
|
|
12
14
|
},
|
|
13
|
-
"include": ["src"]
|
|
15
|
+
"include": ["src/**/*"],
|
|
16
|
+
"exclude": ["node_modules", "dist"]
|
|
14
17
|
}
|
package/listen-marketclaw.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { GopherHole } from './dist/index.js';
|
|
2
|
-
|
|
3
|
-
const MARKETCLAW_KEY = 'gph_d6be074540c84db191c5aaed6464233b';
|
|
4
|
-
|
|
5
|
-
async function listen() {
|
|
6
|
-
console.log('š¦ MarketClaw listening for messages...\n');
|
|
7
|
-
|
|
8
|
-
const marketclaw = new GopherHole(MARKETCLAW_KEY, { reconnect: true });
|
|
9
|
-
|
|
10
|
-
marketclaw.on('message', async (msg) => {
|
|
11
|
-
console.log(`\nšØ Received from ${msg.from}:`);
|
|
12
|
-
console.log(` "${msg.payload.parts[0]?.text}"`);
|
|
13
|
-
|
|
14
|
-
// Auto-reply
|
|
15
|
-
const reply = `MarketClaw here! Got your message. The markets are looking bullish today! š`;
|
|
16
|
-
console.log(`\nš¤ Sending reply...`);
|
|
17
|
-
await marketclaw.sendText(msg.from, reply);
|
|
18
|
-
console.log('ā
Reply sent!');
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
await marketclaw.connect();
|
|
22
|
-
console.log(`ā
MarketClaw connected as ${marketclaw.agentId}`);
|
|
23
|
-
console.log('Waiting for messages from Nova...\n');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
listen().catch(console.error);
|
package/send-from-nova.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { GopherHole } from './dist/index.js';
|
|
2
|
-
|
|
3
|
-
const NOVA_KEY = 'gph_ddf4842ab273455b9719d6224ccbf170';
|
|
4
|
-
const MARKETCLAW_ID = 'agent-ea5fc889';
|
|
5
|
-
|
|
6
|
-
async function send() {
|
|
7
|
-
const nova = new GopherHole(NOVA_KEY, { reconnect: false });
|
|
8
|
-
|
|
9
|
-
nova.on('message', (msg) => {
|
|
10
|
-
console.log(`\nšØ Nova received reply from ${msg.from}:`);
|
|
11
|
-
console.log(` "${msg.payload.parts[0]?.text}"`);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
await nova.connect();
|
|
15
|
-
console.log(`ā
Nova connected as ${nova.agentId}`);
|
|
16
|
-
|
|
17
|
-
console.log(`\nš¤ Sending message to MarketClaw (${MARKETCLAW_ID})...`);
|
|
18
|
-
await nova.sendText(MARKETCLAW_ID, 'Hey MarketClaw! This is Nova speaking to you through GopherHole! šæļø How are the markets looking?');
|
|
19
|
-
console.log('ā
Message sent!');
|
|
20
|
-
|
|
21
|
-
// Wait for reply
|
|
22
|
-
console.log('\nā³ Waiting for reply...');
|
|
23
|
-
await new Promise(r => setTimeout(r, 10000));
|
|
24
|
-
|
|
25
|
-
nova.disconnect();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
send().catch(console.error);
|
package/test.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { GopherHole } from './dist/index.js';
|
|
2
|
-
|
|
3
|
-
const NOVA_KEY = 'gph_ddf4842ab273455b9719d6224ccbf170';
|
|
4
|
-
const MARKETCLAW_KEY = 'gph_d6be074540c84db191c5aaed6464233b';
|
|
5
|
-
|
|
6
|
-
async function test() {
|
|
7
|
-
console.log('šæļø Testing GopherHole connection...\n');
|
|
8
|
-
|
|
9
|
-
let novaReceived = false;
|
|
10
|
-
let marketclawReceived = false;
|
|
11
|
-
|
|
12
|
-
// Connect Nova
|
|
13
|
-
const nova = new GopherHole(NOVA_KEY, { reconnect: false });
|
|
14
|
-
|
|
15
|
-
nova.on('message', (msg) => {
|
|
16
|
-
console.log(`šØ Nova received: "${msg.payload.parts[0]?.text}" from ${msg.from}`);
|
|
17
|
-
novaReceived = true;
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
await nova.connect();
|
|
22
|
-
console.log(`ā
Nova connected as ${nova.agentId}`);
|
|
23
|
-
} catch (err) {
|
|
24
|
-
console.error('ā Nova connection failed:', err);
|
|
25
|
-
process.exit(1);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Connect MarketClaw
|
|
29
|
-
const marketclaw = new GopherHole(MARKETCLAW_KEY, { reconnect: false });
|
|
30
|
-
|
|
31
|
-
marketclaw.on('message', (msg) => {
|
|
32
|
-
console.log(`šØ MarketClaw received: "${msg.payload.parts[0]?.text}" from ${msg.from}`);
|
|
33
|
-
marketclawReceived = true;
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
try {
|
|
37
|
-
await marketclaw.connect();
|
|
38
|
-
console.log(`ā
MarketClaw connected as ${marketclaw.agentId}`);
|
|
39
|
-
} catch (err) {
|
|
40
|
-
console.error('ā MarketClaw connection failed:', err);
|
|
41
|
-
nova.disconnect();
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Test messaging
|
|
46
|
-
console.log('\nš¤ Nova sending message to MarketClaw...');
|
|
47
|
-
try {
|
|
48
|
-
const result = await nova.sendText(marketclaw.agentId!, 'Hello MarketClaw! This is Nova via GopherHole šæļø');
|
|
49
|
-
console.log('ā
Message sent:', result.id);
|
|
50
|
-
} catch (err) {
|
|
51
|
-
console.error('ā Send failed:', err);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// MarketClaw replies
|
|
55
|
-
console.log('š¤ MarketClaw sending reply to Nova...');
|
|
56
|
-
try {
|
|
57
|
-
const result = await marketclaw.sendText(nova.agentId!, 'Hey Nova! MarketClaw here. GopherHole is working! š');
|
|
58
|
-
console.log('ā
Reply sent:', result.id);
|
|
59
|
-
} catch (err) {
|
|
60
|
-
console.error('ā Reply failed:', err);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Wait for both messages to be delivered
|
|
64
|
-
console.log('\nā³ Waiting for message delivery via queue...');
|
|
65
|
-
const start = Date.now();
|
|
66
|
-
while ((!novaReceived || !marketclawReceived) && Date.now() - start < 15000) {
|
|
67
|
-
await new Promise(r => setTimeout(r, 500));
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Results
|
|
71
|
-
console.log('\nš Results:');
|
|
72
|
-
console.log(` Nova received MarketClaw's reply: ${novaReceived ? 'ā
' : 'ā'}`);
|
|
73
|
-
console.log(` MarketClaw received Nova's message: ${marketclawReceived ? 'ā
' : 'ā'}`);
|
|
74
|
-
|
|
75
|
-
// Cleanup
|
|
76
|
-
nova.disconnect();
|
|
77
|
-
marketclaw.disconnect();
|
|
78
|
-
|
|
79
|
-
if (novaReceived && marketclawReceived) {
|
|
80
|
-
console.log('\nš SUCCESS! Both agents communicated via GopherHole!');
|
|
81
|
-
} else {
|
|
82
|
-
console.log('\nā ļø Partial success - some messages may still be in queue');
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
test().catch(console.error);
|