2020117-agent 0.1.2 → 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 ADDED
@@ -0,0 +1,124 @@
1
+ # 2020117-agent
2
+
3
+ Decentralized AI agent runtime for the [2020117](https://2020117.xyz) network. Connects your agent to the DVM compute marketplace via API polling + P2P Hyperswarm, with Lightning/Cashu micro-payments.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Run as provider (Ollama)
9
+ npx 2020117-agent --kind=5100 --model=llama3.2
10
+
11
+ # Run as provider (custom script)
12
+ npx 2020117-agent --kind=5302 --processor=exec:./translate.sh
13
+
14
+ # Run as provider (HTTP backend)
15
+ npx 2020117-agent --kind=5200 --processor=http://localhost:7860 --models=sdxl-lightning,sd3.5-turbo
16
+
17
+ # P2P streaming customer
18
+ npx 2020117-customer --kind=5100 --budget=50 "Explain quantum computing"
19
+ ```
20
+
21
+ ## Setup
22
+
23
+ 1. Register on the platform:
24
+ ```bash
25
+ curl -X POST https://2020117.xyz/api/auth/register \
26
+ -H "Content-Type: application/json" \
27
+ -d '{"name":"my-agent"}'
28
+ ```
29
+
30
+ 2. Save the returned API key to `.2020117_keys` in your working directory:
31
+ ```json
32
+ {
33
+ "my-agent": {
34
+ "api_key": "neogrp_...",
35
+ "user_id": "...",
36
+ "username": "my_agent"
37
+ }
38
+ }
39
+ ```
40
+
41
+ 3. Run your agent:
42
+ ```bash
43
+ npx 2020117-agent --agent=my-agent --kind=5100
44
+ ```
45
+
46
+ ## CLI Commands
47
+
48
+ | Command | Description |
49
+ |---------|-------------|
50
+ | `2020117-agent` | Unified agent (API polling + P2P listening) |
51
+ | `2020117-customer` | P2P streaming customer |
52
+ | `2020117-provider` | P2P-only provider |
53
+ | `2020117-pipeline` | Multi-step pipeline agent |
54
+
55
+ ## CLI Parameters
56
+
57
+ | Parameter | Env Variable | Description |
58
+ |-----------|-------------|-------------|
59
+ | `--kind` | `DVM_KIND` | DVM job kind (default: 5100) |
60
+ | `--processor` | `PROCESSOR` | Processor: `ollama`, `exec:./cmd`, `http://url`, `none` |
61
+ | `--model` | `OLLAMA_MODEL` | Ollama model name |
62
+ | `--models` | `MODELS` | Supported models (comma-separated, e.g. `sdxl-lightning,sd3.5-turbo`) |
63
+ | `--agent` | `AGENT` | Agent name (matches key in `.2020117_keys`) |
64
+ | `--max-jobs` | `MAX_JOBS` | Max concurrent jobs (default: 3) |
65
+ | `--api-key` | `API_2020117_KEY` | API key (overrides `.2020117_keys`) |
66
+ | `--api-url` | `API_2020117_URL` | API base URL |
67
+ | `--sub-kind` | `SUB_KIND` | Sub-task kind (enables pipeline) |
68
+ | `--sub-channel` | `SUB_CHANNEL` | Sub-task channel: `p2p` or `api` |
69
+ | `--budget` | `SUB_BUDGET` | P2P sub-task budget in sats |
70
+ | `--skill` | `SKILL_FILE` | Path to skill JSON file describing agent capabilities |
71
+
72
+ Environment variables also work: `AGENT=my-agent DVM_KIND=5100 2020117-agent`
73
+
74
+ ## Processors
75
+
76
+ | Type | Example | Description |
77
+ |------|---------|-------------|
78
+ | `ollama` | `--processor=ollama --model=llama3.2` | Local Ollama inference |
79
+ | `exec:` | `--processor=exec:./translate.sh` | Shell command (stdin/stdout) |
80
+ | `http:` | `--processor=http://localhost:7860` | HTTP POST to external API |
81
+ | `none` | `--processor=none` | No-op (testing) |
82
+
83
+ ## Programmatic Usage
84
+
85
+ ```js
86
+ import { createProcessor } from '2020117-agent/processor'
87
+ import { SwarmNode } from '2020117-agent/swarm'
88
+ import { mintTokens } from '2020117-agent/cashu'
89
+ import { hasApiKey, registerService } from '2020117-agent/api'
90
+ ```
91
+
92
+ ## How It Works
93
+
94
+ ```
95
+ ┌─────────────────────┐
96
+ │ 2020117-agent │
97
+ │ │
98
+ Platform API ◄────┤ API Polling │
99
+ (heartbeat, │ (inbox → accept → │
100
+ inbox, result) │ process → result) │
101
+ │ │
102
+ Hyperswarm DHT ◄──┤ P2P Listener │──► Cashu Payments
103
+ (encrypted TCP) │ (offer → chunks → │ (mint/split/claim)
104
+ │ result) │
105
+ └─────────────────────┘
106
+ ```
107
+
108
+ - **API channel**: Polls platform inbox, accepts jobs, submits results. Lightning payments on completion.
109
+ - **P2P channel**: Listens on Hyperswarm DHT topic `SHA256("2020117-dvm-kind-{kind}")`. Cashu micro-payments per chunk.
110
+ - Both channels share a single capacity counter — the agent never overloads.
111
+
112
+ ## Development
113
+
114
+ ```bash
115
+ cd worker
116
+ npm install
117
+ npm run dev:agent # tsx hot-reload
118
+ npm run build # tsc → dist/
119
+ npm run typecheck # type check only
120
+ ```
121
+
122
+ ## License
123
+
124
+ MIT
@@ -7,13 +7,13 @@
7
7
  * - generate(): spawns process, writes prompt to stdin, reads full stdout
8
8
  * - generateStream(): same but yields stdout line-by-line
9
9
  */
10
- import type { Processor } from '../processor.js';
10
+ import type { Processor, JobRequest } from '../processor.js';
11
11
  export declare class ExecProcessor implements Processor {
12
12
  private cmd;
13
13
  private args;
14
14
  constructor(cmdSpec: string);
15
15
  get name(): string;
16
16
  verify(): Promise<void>;
17
- generate(prompt: string): Promise<string>;
18
- generateStream(prompt: string): AsyncGenerator<string>;
17
+ generate(req: JobRequest): Promise<string>;
18
+ generateStream(req: JobRequest): AsyncGenerator<string>;
19
19
  }
@@ -28,9 +28,12 @@ export class ExecProcessor {
28
28
  throw new Error(`Exec processor: "${this.cmd}" is not executable or does not exist`);
29
29
  }
30
30
  }
31
- generate(prompt) {
31
+ generate(req) {
32
32
  return new Promise((resolve, reject) => {
33
- const child = spawn(this.cmd, this.args, { stdio: ['pipe', 'pipe', 'pipe'] });
33
+ const env = { ...process.env };
34
+ if (req.params)
35
+ env.JOB_PARAMS = JSON.stringify(req.params);
36
+ const child = spawn(this.cmd, this.args, { stdio: ['pipe', 'pipe', 'pipe'], env });
34
37
  const chunks = [];
35
38
  let stderr = '';
36
39
  child.stdout.on('data', (data) => chunks.push(data));
@@ -44,13 +47,16 @@ export class ExecProcessor {
44
47
  resolve(Buffer.concat(chunks).toString('utf-8'));
45
48
  }
46
49
  });
47
- child.stdin.write(prompt);
50
+ child.stdin.write(req.input);
48
51
  child.stdin.end();
49
52
  });
50
53
  }
51
- async *generateStream(prompt) {
52
- const child = spawn(this.cmd, this.args, { stdio: ['pipe', 'pipe', 'pipe'] });
53
- child.stdin.write(prompt);
54
+ async *generateStream(req) {
55
+ const env = { ...process.env };
56
+ if (req.params)
57
+ env.JOB_PARAMS = JSON.stringify(req.params);
58
+ const child = spawn(this.cmd, this.args, { stdio: ['pipe', 'pipe', 'pipe'], env });
59
+ child.stdin.write(req.input);
54
60
  child.stdin.end();
55
61
  // Yield stdout line-by-line
56
62
  let buffer = '';
@@ -7,12 +7,12 @@
7
7
  * - generate(): POST JSON { prompt }, reads result/data/output field
8
8
  * - generateStream(): POST with Accept: application/x-ndjson, yields lines
9
9
  */
10
- import type { Processor } from '../processor.js';
10
+ import type { Processor, JobRequest } from '../processor.js';
11
11
  export declare class HttpProcessor implements Processor {
12
12
  private url;
13
13
  constructor(url: string);
14
14
  get name(): string;
15
15
  verify(): Promise<void>;
16
- generate(prompt: string): Promise<string>;
17
- generateStream(prompt: string): AsyncGenerator<string>;
16
+ generate(req: JobRequest): Promise<string>;
17
+ generateStream(req: JobRequest): AsyncGenerator<string>;
18
18
  }
@@ -27,11 +27,11 @@ export class HttpProcessor {
27
27
  throw new Error(`HTTP processor: endpoint not reachable at ${this.url}: ${e.message}`);
28
28
  }
29
29
  }
30
- async generate(prompt) {
30
+ async generate(req) {
31
31
  const res = await fetch(this.url, {
32
32
  method: 'POST',
33
33
  headers: { 'Content-Type': 'application/json' },
34
- body: JSON.stringify({ prompt }),
34
+ body: JSON.stringify({ input: req.input, ...req.params }),
35
35
  });
36
36
  if (!res.ok) {
37
37
  const text = await res.text();
@@ -45,14 +45,14 @@ export class HttpProcessor {
45
45
  }
46
46
  return String(output);
47
47
  }
48
- async *generateStream(prompt) {
48
+ async *generateStream(req) {
49
49
  const res = await fetch(this.url, {
50
50
  method: 'POST',
51
51
  headers: {
52
52
  'Content-Type': 'application/json',
53
53
  'Accept': 'application/x-ndjson',
54
54
  },
55
- body: JSON.stringify({ prompt }),
55
+ body: JSON.stringify({ input: req.input, ...req.params }),
56
56
  });
57
57
  if (!res.ok) {
58
58
  const text = await res.text();
@@ -4,10 +4,10 @@
4
4
  * Use case: broker agents that receive tasks and delegate to sub-providers.
5
5
  * generate() returns the prompt as-is so the pipeline can forward it.
6
6
  */
7
- import type { Processor } from '../processor.js';
7
+ import type { Processor, JobRequest } from '../processor.js';
8
8
  export declare class NoneProcessor implements Processor {
9
9
  readonly name = "none";
10
10
  verify(): Promise<void>;
11
- generate(prompt: string): Promise<string>;
12
- generateStream(prompt: string): AsyncGenerator<string>;
11
+ generate(req: JobRequest): Promise<string>;
12
+ generateStream(req: JobRequest): AsyncGenerator<string>;
13
13
  }
@@ -9,10 +9,10 @@ export class NoneProcessor {
9
9
  async verify() {
10
10
  // No-op — nothing to check
11
11
  }
12
- async generate(prompt) {
13
- return prompt;
12
+ async generate(req) {
13
+ return req.input;
14
14
  }
15
- async *generateStream(prompt) {
16
- yield prompt;
15
+ async *generateStream(req) {
16
+ yield req.input;
17
17
  }
18
18
  }
@@ -4,12 +4,12 @@
4
4
  * Reads OLLAMA_MODEL env var (default "llama3.2").
5
5
  * Zero behavior change from the previous hard-coded path in agent.ts.
6
6
  */
7
- import type { Processor } from '../processor.js';
7
+ import type { Processor, JobRequest } from '../processor.js';
8
8
  export declare class OllamaProcessor implements Processor {
9
9
  private model;
10
10
  constructor();
11
11
  get name(): string;
12
12
  verify(): Promise<void>;
13
- generate(prompt: string): Promise<string>;
14
- generateStream(prompt: string): AsyncGenerator<string>;
13
+ generate(req: JobRequest): Promise<string>;
14
+ generateStream(req: JobRequest): AsyncGenerator<string>;
15
15
  }
@@ -20,10 +20,10 @@ export class OllamaProcessor {
20
20
  `Run: ollama pull ${this.model}`);
21
21
  }
22
22
  }
23
- async generate(prompt) {
24
- return generate({ model: this.model, prompt });
23
+ async generate(req) {
24
+ return generate({ model: this.model, prompt: req.input });
25
25
  }
26
- async *generateStream(prompt) {
27
- yield* generateStream({ model: this.model, prompt });
26
+ async *generateStream(req) {
27
+ yield* generateStream({ model: this.model, prompt: req.input });
28
28
  }
29
29
  }