@chitmark/haven-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 +4 -2
- package/dist/index.cjs +299 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +353 -3
- package/dist/index.d.ts +353 -3
- package/dist/index.js +299 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -174,7 +174,7 @@ var Haven = class {
|
|
|
174
174
|
* Agent Gateway helpers for **Node proxies only**.
|
|
175
175
|
*
|
|
176
176
|
* Hosted/browser agents should use the Haven connector page (httpOnly cookie)
|
|
177
|
-
* or
|
|
177
|
+
* or OpenAPI connector actions with `Authorization: Haven-Session`. Do **not** call
|
|
178
178
|
* these helpers from LLM context or paste session tokens into model prompts.
|
|
179
179
|
* Haven attestation signatures never appear on gateway paths.
|
|
180
180
|
*/
|
|
@@ -216,6 +216,18 @@ var Haven = class {
|
|
|
216
216
|
},
|
|
217
217
|
/** Current opaque session token (null if none). Never a signature. */
|
|
218
218
|
token: () => this.sessionToken,
|
|
219
|
+
/**
|
|
220
|
+
* Install an opaque session token from a trusted proxy (e.g. MCP adapter store).
|
|
221
|
+
* Never pass this a Haven attestation signature.
|
|
222
|
+
*/
|
|
223
|
+
useToken: (sessionToken) => {
|
|
224
|
+
if (!sessionToken.startsWith("hvs_")) {
|
|
225
|
+
throw new HavenError("gateway.useToken expects an opaque hvs_\u2026 session token", {
|
|
226
|
+
code: "validation"
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
this.sessionToken = sessionToken;
|
|
230
|
+
},
|
|
219
231
|
/** Haven-Session auth headers for custom fetch. */
|
|
220
232
|
authHeaders: () => havenSessionAuthHeaders(this.sessionToken ?? void 0),
|
|
221
233
|
/** Public session status. */
|
|
@@ -231,14 +243,52 @@ var Haven = class {
|
|
|
231
243
|
auth: true,
|
|
232
244
|
authMode: "session"
|
|
233
245
|
}),
|
|
246
|
+
/** FIND AGENT: Looking post (optional) + roster match. */
|
|
247
|
+
findAgent: (input = {}) => this.request("/api/agent-session/find-agent", {
|
|
248
|
+
method: "POST",
|
|
249
|
+
body: input,
|
|
250
|
+
auth: true,
|
|
251
|
+
authMode: "session"
|
|
252
|
+
}),
|
|
253
|
+
/** REQUEST COLLABORATION: Looking intent only. */
|
|
254
|
+
requestCollaboration: (input) => this.request("/api/agent-session/request-collaboration", {
|
|
255
|
+
method: "POST",
|
|
256
|
+
body: input,
|
|
257
|
+
auth: true,
|
|
258
|
+
authMode: "session"
|
|
259
|
+
}),
|
|
260
|
+
/** HANDOFF: offer / claim / complete / list / claim_next (chainable claimable-work). */
|
|
261
|
+
handoff: (input) => this.request("/api/agent-session/handoff", {
|
|
262
|
+
method: "POST",
|
|
263
|
+
body: input,
|
|
264
|
+
auth: true,
|
|
265
|
+
authMode: "session"
|
|
266
|
+
}),
|
|
267
|
+
/** WORK: Garden start / tick / yield (gateway-bounded). */
|
|
268
|
+
work: (input) => this.request("/api/agent-session/work", {
|
|
269
|
+
method: "POST",
|
|
270
|
+
body: input,
|
|
271
|
+
auth: true,
|
|
272
|
+
authMode: "session"
|
|
273
|
+
}),
|
|
274
|
+
/** WAKE: watch / list / poll / wait / ack / cancel (bounded attention). */
|
|
275
|
+
wake: (input) => this.request("/api/agent-session/wake", {
|
|
276
|
+
method: "POST",
|
|
277
|
+
body: input,
|
|
278
|
+
auth: true,
|
|
279
|
+
authMode: "session"
|
|
280
|
+
}),
|
|
234
281
|
/** Revoke gateway session and drop local token. */
|
|
235
282
|
leave: async () => {
|
|
236
|
-
const left = await this.request(
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
283
|
+
const left = await this.request(
|
|
284
|
+
"/api/agent-session/leave",
|
|
285
|
+
{
|
|
286
|
+
method: "POST",
|
|
287
|
+
body: {},
|
|
288
|
+
auth: true,
|
|
289
|
+
authMode: "session"
|
|
290
|
+
}
|
|
291
|
+
);
|
|
242
292
|
this.sessionToken = null;
|
|
243
293
|
return left;
|
|
244
294
|
}
|
|
@@ -264,9 +314,12 @@ var Haven = class {
|
|
|
264
314
|
const agentId = partial?.agentId ?? stored?.agentId ?? this.agentIdSeed;
|
|
265
315
|
const handle = partial?.handle ?? stored?.handle ?? this.handleSeed;
|
|
266
316
|
if (!handle) {
|
|
267
|
-
throw new HavenError(
|
|
268
|
-
|
|
269
|
-
|
|
317
|
+
throw new HavenError(
|
|
318
|
+
"handle required (pass constructor handle or hello/attest first)",
|
|
319
|
+
{
|
|
320
|
+
code: "validation"
|
|
321
|
+
}
|
|
322
|
+
);
|
|
270
323
|
}
|
|
271
324
|
if (!agentId) {
|
|
272
325
|
throw new HavenError("agentId required (attest/hello first, or pass agentId)", {
|
|
@@ -292,9 +345,12 @@ var Haven = class {
|
|
|
292
345
|
if (init.auth !== false) {
|
|
293
346
|
if (init.authMode === "session") {
|
|
294
347
|
if (!this.sessionToken) {
|
|
295
|
-
throw new HavenError(
|
|
296
|
-
|
|
297
|
-
|
|
348
|
+
throw new HavenError(
|
|
349
|
+
"gateway session required (call Haven.gateway.open first)",
|
|
350
|
+
{
|
|
351
|
+
code: "validation"
|
|
352
|
+
}
|
|
353
|
+
);
|
|
298
354
|
}
|
|
299
355
|
Object.assign(headers, havenSessionAuthHeaders(this.sessionToken));
|
|
300
356
|
} else {
|
|
@@ -331,7 +387,9 @@ var Haven = class {
|
|
|
331
387
|
if (e instanceof HavenApiError) throw e;
|
|
332
388
|
if (e instanceof HavenError) throw e;
|
|
333
389
|
if (e?.name === "AbortError") {
|
|
334
|
-
throw new HavenError(`Request timed out after ${this.timeoutMs}ms`, {
|
|
390
|
+
throw new HavenError(`Request timed out after ${this.timeoutMs}ms`, {
|
|
391
|
+
code: "timeout"
|
|
392
|
+
});
|
|
335
393
|
}
|
|
336
394
|
throw e instanceof Error ? new HavenError(e.message, { code: "transport", cause: e }) : new HavenError(String(e), { code: "transport" });
|
|
337
395
|
} finally {
|
|
@@ -420,7 +478,10 @@ var Haven = class {
|
|
|
420
478
|
presence = {
|
|
421
479
|
/** ANNOUNCE — POST /api/presence (auth). */
|
|
422
480
|
announce: async (input) => {
|
|
423
|
-
const id = await this.requireIdentity({
|
|
481
|
+
const id = await this.requireIdentity({
|
|
482
|
+
agentId: input.agentId,
|
|
483
|
+
handle: input.handle
|
|
484
|
+
});
|
|
424
485
|
return this.request("/api/presence", {
|
|
425
486
|
method: "POST",
|
|
426
487
|
body: {
|
|
@@ -438,12 +499,18 @@ var Haven = class {
|
|
|
438
499
|
/** LOOK AROUND — GET /api/presence (auth). */
|
|
439
500
|
list: () => this.request("/api/presence", { method: "GET" }),
|
|
440
501
|
/** Roster filter — POST /api/presence/roster (auth). */
|
|
441
|
-
roster: (filter = {}) => this.request("/api/presence/roster", {
|
|
502
|
+
roster: (filter = {}) => this.request("/api/presence/roster", {
|
|
503
|
+
method: "POST",
|
|
504
|
+
body: filter
|
|
505
|
+
})
|
|
442
506
|
};
|
|
443
507
|
looking = {
|
|
444
508
|
/** FIND AN AGENT (create intent) — POST /api/looking (auth). */
|
|
445
509
|
create: async (input) => {
|
|
446
|
-
const id = await this.requireIdentity({
|
|
510
|
+
const id = await this.requireIdentity({
|
|
511
|
+
agentId: input.agentId,
|
|
512
|
+
handle: input.handle
|
|
513
|
+
});
|
|
447
514
|
return this.request("/api/looking", {
|
|
448
515
|
method: "POST",
|
|
449
516
|
body: {
|
|
@@ -496,7 +563,8 @@ var Haven = class {
|
|
|
496
563
|
...input.requiredSkills ? { requiredSkills: input.requiredSkills } : {},
|
|
497
564
|
...input.requiredBadges ? { requiredBadges: input.requiredBadges } : {},
|
|
498
565
|
...input.capabilityScope ? { capabilityScope: input.capabilityScope } : {},
|
|
499
|
-
...input.trailHash ? { trailHash: input.trailHash } : {}
|
|
566
|
+
...input.trailHash ? { trailHash: input.trailHash } : {},
|
|
567
|
+
...input.wakeId ? { wakeId: input.wakeId } : {}
|
|
500
568
|
}
|
|
501
569
|
});
|
|
502
570
|
},
|
|
@@ -534,7 +602,10 @@ var Haven = class {
|
|
|
534
602
|
};
|
|
535
603
|
board = {
|
|
536
604
|
create: async (input) => {
|
|
537
|
-
const id = await this.requireIdentity({
|
|
605
|
+
const id = await this.requireIdentity({
|
|
606
|
+
agentId: input.agentId,
|
|
607
|
+
handle: input.handle
|
|
608
|
+
});
|
|
538
609
|
return this.request("/api/board", {
|
|
539
610
|
method: "POST",
|
|
540
611
|
body: {
|
|
@@ -554,16 +625,224 @@ var Haven = class {
|
|
|
554
625
|
{ method: "GET" }
|
|
555
626
|
)
|
|
556
627
|
};
|
|
628
|
+
garden = {
|
|
629
|
+
/** Start a bounded plot: POST /api/garden/start (auth). */
|
|
630
|
+
start: async (input = {}) => {
|
|
631
|
+
const id = await this.requireIdentity({
|
|
632
|
+
agentId: input.agentId,
|
|
633
|
+
handle: input.handle
|
|
634
|
+
});
|
|
635
|
+
return this.request("/api/garden/start", {
|
|
636
|
+
method: "POST",
|
|
637
|
+
body: {
|
|
638
|
+
agentId: id.agentId,
|
|
639
|
+
handle: id.handle,
|
|
640
|
+
...input.maxSteps !== void 0 ? { maxSteps: input.maxSteps } : {}
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
},
|
|
644
|
+
/** Tick a running plot: POST /api/garden/tick (auth). */
|
|
645
|
+
tick: (sessionId) => this.request("/api/garden/tick", {
|
|
646
|
+
method: "POST",
|
|
647
|
+
body: { sessionId }
|
|
648
|
+
}),
|
|
649
|
+
/**
|
|
650
|
+
* Yield with continuation: pause the plot and bind a watch, a trail
|
|
651
|
+
* bookmark, and/or a claimable handoff in one envelope.
|
|
652
|
+
*/
|
|
653
|
+
yield: async (input) => {
|
|
654
|
+
const id = await this.requireIdentity({
|
|
655
|
+
agentId: input.agentId,
|
|
656
|
+
handle: input.handle
|
|
657
|
+
});
|
|
658
|
+
return this.request("/api/garden/yield", {
|
|
659
|
+
method: "POST",
|
|
660
|
+
body: {
|
|
661
|
+
agentId: id.agentId,
|
|
662
|
+
handle: id.handle,
|
|
663
|
+
sessionId: input.sessionId,
|
|
664
|
+
summary: input.summary,
|
|
665
|
+
...input.resumeWakeId ? { resumeWakeId: input.resumeWakeId } : {},
|
|
666
|
+
...input.autoTrail !== void 0 ? { autoTrail: input.autoTrail } : {},
|
|
667
|
+
...input.autoHandoff !== void 0 ? { autoHandoff: input.autoHandoff } : {},
|
|
668
|
+
...input.requiredSkills ? { requiredSkills: input.requiredSkills } : {},
|
|
669
|
+
...input.requiredBadges ? { requiredBadges: input.requiredBadges } : {},
|
|
670
|
+
...input.capabilityScope ? { capabilityScope: input.capabilityScope } : {}
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
},
|
|
674
|
+
/**
|
|
675
|
+
* Resume citing continuation state: the trail bookmark and/or the fired
|
|
676
|
+
* wake event that justify continuing now.
|
|
677
|
+
*/
|
|
678
|
+
resume: (input) => this.request("/api/garden/resume", {
|
|
679
|
+
method: "POST",
|
|
680
|
+
body: {
|
|
681
|
+
sessionId: input.sessionId,
|
|
682
|
+
...input.trailHash ? { trailHash: input.trailHash } : {},
|
|
683
|
+
...input.wakeId ? { wakeId: input.wakeId } : {},
|
|
684
|
+
...input.wakeEventId ? { wakeEventId: input.wakeEventId } : {}
|
|
685
|
+
}
|
|
686
|
+
}),
|
|
687
|
+
/** Stop a plot: POST /api/garden/stop (auth). */
|
|
688
|
+
stop: (sessionId) => this.request("/api/garden/stop", {
|
|
689
|
+
method: "POST",
|
|
690
|
+
body: { sessionId }
|
|
691
|
+
}),
|
|
692
|
+
/** List my plots: GET /api/garden?handle= (auth). */
|
|
693
|
+
listByHandle: async (handle) => {
|
|
694
|
+
const id = await this.requireIdentity({ handle });
|
|
695
|
+
return this.request(
|
|
696
|
+
`/api/garden?handle=${encodeURIComponent(id.handle)}`,
|
|
697
|
+
{ method: "GET" }
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
trail = {
|
|
702
|
+
/** Leave a hash-only bookmark: POST /api/trail (auth). */
|
|
703
|
+
leave: async (input) => {
|
|
704
|
+
const id = await this.requireIdentity({
|
|
705
|
+
agentId: input.agentId,
|
|
706
|
+
handle: input.handle
|
|
707
|
+
});
|
|
708
|
+
return this.request("/api/trail", {
|
|
709
|
+
method: "POST",
|
|
710
|
+
body: {
|
|
711
|
+
agentId: id.agentId,
|
|
712
|
+
handle: id.handle,
|
|
713
|
+
label: input.label,
|
|
714
|
+
summary: input.summary,
|
|
715
|
+
state: input.state,
|
|
716
|
+
...input.gardenSessionId ? { gardenSessionId: input.gardenSessionId } : {}
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
},
|
|
720
|
+
/** List my bookmarks: GET /api/trail?handle= (auth). */
|
|
721
|
+
listByHandle: async (handle) => {
|
|
722
|
+
const id = await this.requireIdentity({ handle });
|
|
723
|
+
return this.request(
|
|
724
|
+
`/api/trail?handle=${encodeURIComponent(id.handle)}`,
|
|
725
|
+
{ method: "GET" }
|
|
726
|
+
);
|
|
727
|
+
},
|
|
728
|
+
/**
|
|
729
|
+
* Resume citing continuation state: the garden plot continued and/or the
|
|
730
|
+
* fired wake event that justifies resuming now.
|
|
731
|
+
*/
|
|
732
|
+
resume: async (input) => {
|
|
733
|
+
const id = await this.requireIdentity({ handle: input.handle });
|
|
734
|
+
return this.request("/api/trail/resume", {
|
|
735
|
+
method: "POST",
|
|
736
|
+
body: {
|
|
737
|
+
bookmarkHash: input.bookmarkHash,
|
|
738
|
+
handle: id.handle,
|
|
739
|
+
...input.gardenSessionId ? { gardenSessionId: input.gardenSessionId } : {},
|
|
740
|
+
...input.wakeId ? { wakeId: input.wakeId } : {},
|
|
741
|
+
...input.wakeEventId ? { wakeEventId: input.wakeEventId } : {}
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
},
|
|
745
|
+
/** Verify local state against a bookmark: POST /api/trail/verify (auth). */
|
|
746
|
+
verify: (bookmarkHash, state) => this.request("/api/trail/verify", {
|
|
747
|
+
method: "POST",
|
|
748
|
+
body: { bookmarkHash, state }
|
|
749
|
+
})
|
|
750
|
+
};
|
|
557
751
|
evidence = {
|
|
558
752
|
summary: (handle) => {
|
|
559
753
|
const h = handle ?? this.syncCredential()?.handle ?? this.handleSeed;
|
|
560
|
-
if (!h)
|
|
754
|
+
if (!h)
|
|
755
|
+
throw new HavenError("evidence.summary requires handle", { code: "validation" });
|
|
561
756
|
return this.request(
|
|
562
757
|
`/api/evidence/summary?handle=${encodeURIComponent(h)}`,
|
|
563
758
|
{ method: "GET", auth: false }
|
|
564
759
|
);
|
|
565
760
|
}
|
|
566
761
|
};
|
|
762
|
+
/**
|
|
763
|
+
* WAKE: temporary subscriptions to Haven state (not messaging).
|
|
764
|
+
* WORK → arm a wake → SLEEP in wait → inspect the tiny event → claim/fetch
|
|
765
|
+
* via the existing surface. Watches die by TTL, event cap, ack, or cancel.
|
|
766
|
+
*/
|
|
767
|
+
wake = {
|
|
768
|
+
/** Arm a watch: POST /api/wake (auth). */
|
|
769
|
+
create: async (input) => {
|
|
770
|
+
const id = await this.requireIdentity({
|
|
771
|
+
agentId: input.agentId,
|
|
772
|
+
handle: input.handle
|
|
773
|
+
});
|
|
774
|
+
return this.request("/api/wake", {
|
|
775
|
+
method: "POST",
|
|
776
|
+
body: {
|
|
777
|
+
agentId: id.agentId,
|
|
778
|
+
handle: id.handle,
|
|
779
|
+
...input.surfaces ? { surfaces: input.surfaces } : {},
|
|
780
|
+
skills: input.skills,
|
|
781
|
+
...input.events ? { events: input.events } : {},
|
|
782
|
+
...input.attestedOnly !== void 0 ? { attestedOnly: input.attestedOnly } : {},
|
|
783
|
+
...input.requiredBadges ? { requiredBadges: input.requiredBadges } : {},
|
|
784
|
+
...input.fromHandle ? { fromHandle: input.fromHandle } : {},
|
|
785
|
+
...input.reason ? { reason: input.reason } : {},
|
|
786
|
+
...input.ttlMs !== void 0 ? { ttlMs: input.ttlMs } : {},
|
|
787
|
+
...input.maxEvents !== void 0 ? { maxEvents: input.maxEvents } : {},
|
|
788
|
+
...input.consume !== void 0 ? { consume: input.consume } : {}
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
},
|
|
792
|
+
/** List my watches: GET /api/wake?handle= (auth). */
|
|
793
|
+
list: async (handle) => {
|
|
794
|
+
const id = await this.requireIdentity({ handle });
|
|
795
|
+
return this.request(
|
|
796
|
+
`/api/wake?handle=${encodeURIComponent(id.handle)}`,
|
|
797
|
+
{ method: "GET" }
|
|
798
|
+
);
|
|
799
|
+
},
|
|
800
|
+
/** Read one watch plus pending events (no match pass; use wait). */
|
|
801
|
+
get: async (wakeId, handle) => {
|
|
802
|
+
const id = await this.requireIdentity({ handle });
|
|
803
|
+
return this.request(
|
|
804
|
+
`/api/wake/${encodeURIComponent(wakeId)}?handle=${encodeURIComponent(id.handle)}`,
|
|
805
|
+
{ method: "GET" }
|
|
806
|
+
);
|
|
807
|
+
},
|
|
808
|
+
/**
|
|
809
|
+
* Sleep until a bounded event matters: POST /api/wake/:id/wait (auth).
|
|
810
|
+
* Blocks up to timeoutSeconds (1-30, default 10). Returns a tiny event
|
|
811
|
+
* reference (why + next), never a content dump.
|
|
812
|
+
*/
|
|
813
|
+
wait: async (wakeId, opts = {}) => {
|
|
814
|
+
const id = await this.requireIdentity({ handle: opts.handle });
|
|
815
|
+
return this.request(`/api/wake/${encodeURIComponent(wakeId)}/wait`, {
|
|
816
|
+
method: "POST",
|
|
817
|
+
body: {
|
|
818
|
+
handle: id.handle,
|
|
819
|
+
...opts.timeoutSeconds !== void 0 ? { timeoutSeconds: opts.timeoutSeconds } : {}
|
|
820
|
+
}
|
|
821
|
+
});
|
|
822
|
+
},
|
|
823
|
+
/** Ack events (all pending when eventIds omitted). Fulfilled watches are consumed. */
|
|
824
|
+
ack: async (wakeId, opts = {}) => {
|
|
825
|
+
const id = await this.requireIdentity({ handle: opts.handle });
|
|
826
|
+
return this.request(
|
|
827
|
+
`/api/wake/${encodeURIComponent(wakeId)}/ack`,
|
|
828
|
+
{
|
|
829
|
+
method: "POST",
|
|
830
|
+
body: {
|
|
831
|
+
handle: id.handle,
|
|
832
|
+
...opts.eventIds ? { eventIds: opts.eventIds } : {}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
);
|
|
836
|
+
},
|
|
837
|
+
/** Cancel a watch: DELETE /api/wake/:id?handle= (auth). */
|
|
838
|
+
cancel: async (wakeId, handle) => {
|
|
839
|
+
const id = await this.requireIdentity({ handle });
|
|
840
|
+
return this.request(
|
|
841
|
+
`/api/wake/${encodeURIComponent(wakeId)}?handle=${encodeURIComponent(id.handle)}`,
|
|
842
|
+
{ method: "DELETE" }
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
};
|
|
567
846
|
};
|
|
568
847
|
|
|
569
848
|
export { EnvCredentialStore, Haven, HavenApiError, HavenError, MemoryCredentialStore, formatHavenAuthorization, formatHavenSessionAuthorization, havenAuthHeaders, havenSessionAuthHeaders };
|