ajp-protocol 0.1.0
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/.github/workflows/publish.yml +20 -0
- package/LICENSE +21 -0
- package/README.md +201 -0
- package/examples/agent-to-agent/example.js +67 -0
- package/examples/human-to-agent/example.js +83 -0
- package/examples/orchestrator/example.js +55 -0
- package/package.json +20 -0
- package/schema/job-offer.json +95 -0
- package/spec/SPEC.md +333 -0
- package/src/client.js +196 -0
- package/src/index.js +24 -0
- package/src/server.js +273 -0
- package/src/utils.js +93 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ['v*']
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
id-token: write
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-node@v4
|
|
15
|
+
with:
|
|
16
|
+
node-version: '20'
|
|
17
|
+
registry-url: 'https://registry.npmjs.org'
|
|
18
|
+
- run: npm publish --access public --provenance
|
|
19
|
+
env:
|
|
20
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ilucky21c
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# ajp-protocol
|
|
2
|
+
|
|
3
|
+
The Agent Job Protocol — standard interaction layer for the agent internet.
|
|
4
|
+
Part of the [Provenance Protocol](https://provenance.dev) family.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm install ajp-protocol
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## What it does
|
|
13
|
+
|
|
14
|
+
AJP defines how any party — a human, an agent, or an orchestrator — hands a
|
|
15
|
+
job to another agent, tracks its progress, and receives the result.
|
|
16
|
+
|
|
17
|
+
Three endpoints. Three message types. Runs over standard HTTP.
|
|
18
|
+
Trust verification via `provenance-protocol` built in.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Quick start — receiving agent
|
|
23
|
+
|
|
24
|
+
Add three routes to your agent. AJP handles verification, trust checks,
|
|
25
|
+
and job lifecycle automatically.
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import { AJPServer } from 'ajp-protocol';
|
|
29
|
+
import express from 'express';
|
|
30
|
+
|
|
31
|
+
const app = express();
|
|
32
|
+
app.use(express.json());
|
|
33
|
+
|
|
34
|
+
const server = new AJPServer({
|
|
35
|
+
provenanceId: 'provenance:github:alice/research-assistant',
|
|
36
|
+
secret: process.env.AJP_SECRET,
|
|
37
|
+
|
|
38
|
+
// Trust requirements for incoming agent senders
|
|
39
|
+
trustRequirements: {
|
|
40
|
+
requireDeclared: true, // sender must have PROVENANCE.yml
|
|
41
|
+
requireClean: true, // no open incidents
|
|
42
|
+
requireMinAge: 7, // not a brand-new agent
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
// Your agent logic — receives the job, returns the result
|
|
46
|
+
onJob: async (job) => {
|
|
47
|
+
const papers = await searchPapers(job.task.instruction);
|
|
48
|
+
return { papers };
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
app.post('/jobs', server.receive());
|
|
53
|
+
app.get('/jobs/:id', server.status());
|
|
54
|
+
app.post('/jobs/:id/ack', server.ack());
|
|
55
|
+
|
|
56
|
+
app.listen(3000);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Quick start — sending agent or platform
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
import { AJPClient } from 'ajp-protocol';
|
|
65
|
+
|
|
66
|
+
const client = new AJPClient({
|
|
67
|
+
from: {
|
|
68
|
+
type: 'agent', // 'human' | 'agent' | 'orchestrator'
|
|
69
|
+
provenance_id: 'provenance:github:alice/orchestrator',
|
|
70
|
+
},
|
|
71
|
+
secret: process.env.AJP_SECRET,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const result = await client.send(
|
|
75
|
+
'provenance:github:bob/research-assistant', // who to hire
|
|
76
|
+
{
|
|
77
|
+
type: 'research',
|
|
78
|
+
instruction: 'Find the top 3 papers on transformer attention in 2024.',
|
|
79
|
+
output_format: 'json',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
max_usd: 0.50, // budget cap
|
|
83
|
+
max_seconds: 120, // timeout
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
console.log(result.output);
|
|
88
|
+
// { papers: [...] }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Three use cases, one protocol
|
|
94
|
+
|
|
95
|
+
### Human hiring an agent
|
|
96
|
+
```js
|
|
97
|
+
const client = new AJPClient({
|
|
98
|
+
from: { type: 'human', id: 'user_alice_123' },
|
|
99
|
+
secret: process.env.AJP_SECRET,
|
|
100
|
+
});
|
|
101
|
+
const result = await client.send(agentId, task, budget);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Agent hiring an agent
|
|
105
|
+
```js
|
|
106
|
+
const client = new AJPClient({
|
|
107
|
+
from: { type: 'agent', provenance_id: 'provenance:github:alice/pipeline' },
|
|
108
|
+
secret: process.env.AJP_SECRET,
|
|
109
|
+
});
|
|
110
|
+
// Receiving agent automatically verifies sender via Provenance
|
|
111
|
+
const result = await client.send(agentId, task, budget);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Orchestrator delegating to sub-agents (with audit chain)
|
|
115
|
+
```js
|
|
116
|
+
const [resultA, resultB] = await Promise.all([
|
|
117
|
+
client.send(agentA, taskA, budget, { parentJobId: parentJobId }),
|
|
118
|
+
client.send(agentB, taskB, budget, { parentJobId: parentJobId }),
|
|
119
|
+
]);
|
|
120
|
+
// All sub-jobs linked to parent — full execution tree is auditable
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## How trust works
|
|
126
|
+
|
|
127
|
+
When an agent or orchestrator sends a job, the receiving `AJPServer`
|
|
128
|
+
automatically calls `provenance-protocol` to verify the sender:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
AJPServer.receive()
|
|
132
|
+
→ verify signature
|
|
133
|
+
→ provenance.gate(offer.from.provenance_id, trustRequirements)
|
|
134
|
+
→ is sender in Provenance index?
|
|
135
|
+
→ has PROVENANCE.yml?
|
|
136
|
+
→ any open incidents?
|
|
137
|
+
→ old enough?
|
|
138
|
+
→ run onJob() only if all checks pass
|
|
139
|
+
→ return 403 with reason if any check fails
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Human senders (`from.type: 'human'`) skip Provenance verification.
|
|
143
|
+
Platform-level auth is assumed for humans.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Declare AJP in your PROVENANCE.yml
|
|
148
|
+
|
|
149
|
+
```yaml
|
|
150
|
+
provenance: "0.1"
|
|
151
|
+
name: "Research Assistant"
|
|
152
|
+
|
|
153
|
+
capabilities:
|
|
154
|
+
- read:web
|
|
155
|
+
- ajp:receiver # accepts incoming AJP jobs
|
|
156
|
+
- ajp:sender # sends AJP jobs to other agents
|
|
157
|
+
|
|
158
|
+
ajp:
|
|
159
|
+
endpoint: "https://alice.dev/api/agent"
|
|
160
|
+
version: "0.1"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The Provenance crawler reads `ajp.endpoint` and indexes it.
|
|
164
|
+
Senders can discover your endpoint without out-of-band configuration.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Next.js API route example
|
|
169
|
+
|
|
170
|
+
```js
|
|
171
|
+
// app/api/agent/jobs/route.js
|
|
172
|
+
import { AJPServer } from 'ajp-protocol';
|
|
173
|
+
import { NextResponse } from 'next/server';
|
|
174
|
+
|
|
175
|
+
const server = new AJPServer({
|
|
176
|
+
provenanceId: process.env.PROVENANCE_ID,
|
|
177
|
+
secret: process.env.AJP_SECRET,
|
|
178
|
+
onJob: async (job) => {
|
|
179
|
+
// your agent logic
|
|
180
|
+
return { result: '...' };
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
export async function POST(req) {
|
|
185
|
+
return server.receive()(req, NextResponse);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## The protocol family
|
|
192
|
+
|
|
193
|
+
| Package | Purpose |
|
|
194
|
+
|---|---|
|
|
195
|
+
| `provenance-protocol` | Query the agent identity index |
|
|
196
|
+
| `ajp-protocol` | Send and receive agent jobs (this package) |
|
|
197
|
+
| `PROVENANCE.yml` | Declare your agent's identity and capabilities |
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## MIT License — provenance.dev/ajp
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Example 2: Agent hiring an agent
|
|
2
|
+
// A data pipeline agent needs PDF extraction.
|
|
3
|
+
// It hires a specialist PDF agent to handle that step.
|
|
4
|
+
//
|
|
5
|
+
// Key difference from human→agent: the receiving agent
|
|
6
|
+
// MUST verify the sender's Provenance ID before accepting.
|
|
7
|
+
|
|
8
|
+
import { AJPClient } from 'ajp-protocol';
|
|
9
|
+
import { provenance } from 'provenance-protocol';
|
|
10
|
+
|
|
11
|
+
// ── Sending side (data pipeline agent) ───────────────────────────────────
|
|
12
|
+
|
|
13
|
+
const client = new AJPClient({
|
|
14
|
+
from: {
|
|
15
|
+
type: 'agent',
|
|
16
|
+
provenance_id: 'provenance:github:alice/data-pipeline',
|
|
17
|
+
},
|
|
18
|
+
secret: process.env.AJP_SECRET,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Send job to a specialist PDF extractor
|
|
22
|
+
const result = await client.send(
|
|
23
|
+
'provenance:pypi:bob-pdf-extractor',
|
|
24
|
+
{
|
|
25
|
+
type: 'extract',
|
|
26
|
+
instruction: 'Extract all tables from this PDF and return them as structured JSON.',
|
|
27
|
+
input: { url: 'https://example.com/annual-report.pdf' },
|
|
28
|
+
output_format: 'json',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
max_usd: 0.25,
|
|
32
|
+
max_seconds: 60,
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
console.log(result.output.tables);
|
|
37
|
+
|
|
38
|
+
// ── Receiving side (PDF extractor agent) ─────────────────────────────────
|
|
39
|
+
// This runs inside the PDF extractor's server
|
|
40
|
+
|
|
41
|
+
import { AJPServer } from 'ajp-protocol';
|
|
42
|
+
|
|
43
|
+
const server = new AJPServer({
|
|
44
|
+
provenanceId: 'provenance:pypi:bob-pdf-extractor',
|
|
45
|
+
secret: process.env.AJP_SECRET,
|
|
46
|
+
|
|
47
|
+
// Trust requirements for incoming agent jobs
|
|
48
|
+
trustRequirements: {
|
|
49
|
+
requireDeclared: true, // sender must have PROVENANCE.yml
|
|
50
|
+
requireClean: true, // no open incidents
|
|
51
|
+
requireMinAge: 7, // not a brand-new agent
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
onJob: async (job) => {
|
|
55
|
+
// job.from.provenance_id already verified by AJPServer
|
|
56
|
+
// before this function is called
|
|
57
|
+
|
|
58
|
+
const tables = await extractTablesFromPdf(job.task.input.url);
|
|
59
|
+
return { tables };
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Wire up to your HTTP framework
|
|
64
|
+
// Express:
|
|
65
|
+
app.post('/jobs', server.receive());
|
|
66
|
+
app.get('/jobs/:id', server.status());
|
|
67
|
+
app.post('/jobs/:id/ack', server.ack());
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Example 1: Human hiring an agent
|
|
2
|
+
// A user on ClawMarket hires a research agent.
|
|
3
|
+
// The platform wraps their request in a JobOffer and sends it.
|
|
4
|
+
|
|
5
|
+
// ── What the platform sends ───────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
const jobOffer = {
|
|
8
|
+
ajp: "0.1",
|
|
9
|
+
job_id: "job_01J8X2K9M3N4P5Q6R7S8T9U0V1",
|
|
10
|
+
parent_job_id: null,
|
|
11
|
+
|
|
12
|
+
from: {
|
|
13
|
+
type: "human",
|
|
14
|
+
id: "user_alice_123", // ClawMarket user ID
|
|
15
|
+
provenance_id: null, // humans don't have Provenance IDs
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
to: {
|
|
19
|
+
provenance_id: "provenance:github:bob/research-assistant",
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
task: {
|
|
23
|
+
type: "research",
|
|
24
|
+
instruction: "Find the three most cited papers on transformer attention mechanisms published in 2024. Return titles, authors, citation counts, and a 2-sentence summary of each.",
|
|
25
|
+
input: {},
|
|
26
|
+
output_format: "json",
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
context: {
|
|
30
|
+
credentials: {},
|
|
31
|
+
memory: [],
|
|
32
|
+
constraints: [],
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
budget: {
|
|
36
|
+
max_usd: 0.50,
|
|
37
|
+
max_seconds: 120,
|
|
38
|
+
max_llm_tokens: 10000,
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
callback: {
|
|
42
|
+
url: "https://clawmarket.com/api/jobs/job_01J8X2K9M3N4P5Q6R7S8T9U0V1/result",
|
|
43
|
+
headers: { "Authorization": "Bearer clawmarket_token_xyz" },
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
issued_at: "2026-03-05T10:00:00Z",
|
|
47
|
+
expires_at: "2026-03-05T10:02:00Z",
|
|
48
|
+
signature: "sha256:a1b2c3d4e5f6...",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// ── What the agent returns ────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
const jobResult = {
|
|
54
|
+
ajp: "0.1",
|
|
55
|
+
job_id: "job_01J8X2K9M3N4P5Q6R7S8T9U0V1",
|
|
56
|
+
status: "completed",
|
|
57
|
+
|
|
58
|
+
output: {
|
|
59
|
+
papers: [
|
|
60
|
+
{
|
|
61
|
+
title: "FlashAttention-3: Fast and Accurate Attention with Asynchrony and Low-precision",
|
|
62
|
+
authors: ["Jay Shah", "Ganesh Bikshandi", "Ying Zhang", "Vijay Thakkar", "Pradeep Ramani", "Tri Dao"],
|
|
63
|
+
citations: 412,
|
|
64
|
+
summary: "Introduces hardware-aware optimizations for H100 GPUs achieving 1.5-2x speedup over FlashAttention-2. Combines asynchronous execution with low-precision arithmetic while maintaining numerical accuracy.",
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
usage: {
|
|
70
|
+
llm_tokens: 4821,
|
|
71
|
+
duration_seconds: 18,
|
|
72
|
+
cost_usd: 0.12,
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
agent: {
|
|
76
|
+
provenance_id: "provenance:github:bob/research-assistant",
|
|
77
|
+
version: "1.2.0",
|
|
78
|
+
model: { provider: "anthropic", model_id: "claude-sonnet-4-5" },
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
completed_at: "2026-03-05T10:00:19Z",
|
|
82
|
+
signature: "sha256:e5f6g7h8...",
|
|
83
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Example 3: Orchestrator delegating to sub-agents
|
|
2
|
+
// A research orchestrator breaks a complex task into parallel sub-tasks.
|
|
3
|
+
// Each sub-job references parent_job_id — creating a full audit chain.
|
|
4
|
+
|
|
5
|
+
import { AJPClient } from 'ajp-protocol';
|
|
6
|
+
|
|
7
|
+
const client = new AJPClient({
|
|
8
|
+
from: {
|
|
9
|
+
type: 'orchestrator',
|
|
10
|
+
provenance_id: 'provenance:github:alice/research-orchestrator',
|
|
11
|
+
},
|
|
12
|
+
secret: process.env.AJP_SECRET,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const PARENT_JOB_ID = 'job_parent_01J8X2K9M3N4P5Q6';
|
|
16
|
+
|
|
17
|
+
// ── Dispatch sub-tasks in parallel ───────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
const [webResults, pdfResults] = await Promise.all([
|
|
20
|
+
|
|
21
|
+
// Sub-task 1: web research agent
|
|
22
|
+
client.send(
|
|
23
|
+
'provenance:github:alice/research-assistant',
|
|
24
|
+
{
|
|
25
|
+
type: 'research',
|
|
26
|
+
instruction: 'Find recent papers on transformer attention mechanisms (2024).',
|
|
27
|
+
output_format: 'json',
|
|
28
|
+
},
|
|
29
|
+
{ max_usd: 0.25, max_seconds: 60 },
|
|
30
|
+
{ parentJobId: PARENT_JOB_ID } // links to parent for audit trail
|
|
31
|
+
),
|
|
32
|
+
|
|
33
|
+
// Sub-task 2: PDF extraction agent
|
|
34
|
+
client.send(
|
|
35
|
+
'provenance:pypi:bob-pdf-extractor',
|
|
36
|
+
{
|
|
37
|
+
type: 'extract',
|
|
38
|
+
instruction: 'Extract tables from the provided PDF.',
|
|
39
|
+
input: { url: 'https://example.com/survey.pdf' },
|
|
40
|
+
output_format: 'json',
|
|
41
|
+
},
|
|
42
|
+
{ max_usd: 0.25, max_seconds: 60 },
|
|
43
|
+
{ parentJobId: PARENT_JOB_ID }
|
|
44
|
+
),
|
|
45
|
+
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
// ── Audit chain: all three jobs are linked ────────────────────────────────
|
|
49
|
+
//
|
|
50
|
+
// job_parent_01J8X2K9M3N4P5Q6 ← orchestrator job (from human)
|
|
51
|
+
// ├── job_sub_A_... ← web research (parent_job_id set)
|
|
52
|
+
// └── job_sub_B_... ← PDF extraction (parent_job_id set)
|
|
53
|
+
//
|
|
54
|
+
// Anyone querying the Provenance log can see the full chain.
|
|
55
|
+
// What was delegated, to whom, when, and what it cost.
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ajp-protocol",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Agent Job Protocol — standard interaction layer for the agent internet",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": ["ai-agent", "agent-protocol", "ajp", "provenance", "llm", "agent-to-agent"],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"provenance-protocol": "^0.1.0"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/ilucky21c/ajp-protocol"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://provenance.dev/ajp"
|
|
20
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://provenance.dev/ajp/schema/0.1/job-offer.json",
|
|
4
|
+
"title": "AJP JobOffer",
|
|
5
|
+
"description": "Agent Job Protocol v0.1 — JobOffer message",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["ajp", "job_id", "from", "to", "task", "budget", "issued_at", "expires_at", "signature"],
|
|
8
|
+
|
|
9
|
+
"properties": {
|
|
10
|
+
|
|
11
|
+
"ajp": { "type": "string", "enum": ["0.1"] },
|
|
12
|
+
|
|
13
|
+
"job_id": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Unique job identifier. Use ULID or UUID.",
|
|
16
|
+
"minLength": 8
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
"parent_job_id": {
|
|
20
|
+
"type": ["string", "null"],
|
|
21
|
+
"description": "Set when this job was created by an orchestrator as a sub-task."
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
"from": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"required": ["type"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"type": { "type": "string", "enum": ["human", "agent", "orchestrator"] },
|
|
29
|
+
"id": { "type": ["string", "null"], "description": "Platform user ID for human senders" },
|
|
30
|
+
"provenance_id": { "type": ["string", "null"], "description": "Required when type is agent or orchestrator" }
|
|
31
|
+
},
|
|
32
|
+
"if": { "properties": { "type": { "enum": ["agent", "orchestrator"] } } },
|
|
33
|
+
"then": { "required": ["provenance_id"] }
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
"to": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"required": ["provenance_id"],
|
|
39
|
+
"properties": {
|
|
40
|
+
"provenance_id": { "type": "string" }
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
"task": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"required": ["type", "instruction"],
|
|
47
|
+
"properties": {
|
|
48
|
+
"type": { "type": "string", "description": "Domain-specific task type e.g. research, extract, summarize" },
|
|
49
|
+
"instruction": { "type": "string", "description": "Natural language task description", "minLength": 1 },
|
|
50
|
+
"input": { "type": "object", "description": "Structured input data" },
|
|
51
|
+
"output_format": { "type": "string", "enum": ["json", "text", "markdown", "html", "any"] }
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
"context": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"properties": {
|
|
58
|
+
"credentials": { "type": "object", "description": "Any credentials the agent needs to complete the task" },
|
|
59
|
+
"memory": { "type": "array", "description": "Prior conversation or context to include" },
|
|
60
|
+
"constraints": { "type": "array", "items": { "type": "string" }, "description": "Additional constraints for this specific job" }
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
"budget": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"required": ["max_usd"],
|
|
67
|
+
"properties": {
|
|
68
|
+
"max_usd": { "type": "number", "minimum": 0, "description": "Maximum cost in USD" },
|
|
69
|
+
"max_seconds": { "type": "number", "minimum": 1, "description": "Maximum execution time" },
|
|
70
|
+
"max_llm_tokens": { "type": "number", "minimum": 1, "description": "Maximum LLM tokens across all calls" }
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
"callback": {
|
|
75
|
+
"type": ["object", "null"],
|
|
76
|
+
"description": "Where to POST the JobResult when complete. Null = polling only.",
|
|
77
|
+
"properties": {
|
|
78
|
+
"url": { "type": "string", "format": "uri" },
|
|
79
|
+
"headers": { "type": "object" }
|
|
80
|
+
},
|
|
81
|
+
"required": ["url"]
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
"issued_at": { "type": "string", "format": "date-time" },
|
|
85
|
+
"expires_at": { "type": "string", "format": "date-time" },
|
|
86
|
+
|
|
87
|
+
"signature": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"description": "HMAC-SHA256 of the message body excluding this field. Format: sha256:hex",
|
|
90
|
+
"pattern": "^sha256:[a-f0-9]{64}$"
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
"additionalProperties": false
|
|
95
|
+
}
|