@fungi.computer/agar 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +766 -2
- package/dist/agent-message-meta.d.ts +74 -0
- package/dist/agent-message-meta.js +63 -0
- package/dist/agents.d.ts +170 -0
- package/dist/agents.js +218 -0
- package/dist/app-build-contract.d.ts +43 -0
- package/dist/app-build-contract.js +24 -0
- package/dist/apps.d.ts +66 -0
- package/dist/apps.js +47 -0
- package/dist/backend-declaration.d.ts +6 -0
- package/dist/backend-declaration.js +65 -0
- package/dist/backend-definition.d.ts +88 -0
- package/dist/backend-definition.js +158 -0
- package/dist/backend-refusal.d.ts +10 -0
- package/dist/backend-refusal.js +10 -0
- package/dist/backend.d.ts +30 -0
- package/dist/backend.js +28 -0
- package/dist/capabilities.d.ts +30 -0
- package/dist/capabilities.js +50 -0
- package/dist/channels.d.ts +142 -0
- package/dist/channels.js +97 -0
- package/dist/commands.d.ts +33 -0
- package/dist/commands.js +46 -0
- package/dist/computer-contracts.d.ts +73 -0
- package/dist/computer-contracts.js +57 -0
- package/dist/computer.d.ts +294 -0
- package/dist/computer.js +319 -0
- package/dist/connect.d.ts +11 -0
- package/dist/connect.js +211 -0
- package/dist/errors.d.ts +34 -0
- package/dist/errors.js +106 -0
- package/dist/failure.d.ts +2 -0
- package/dist/failure.js +9 -0
- package/dist/files.d.ts +25 -0
- package/dist/files.js +84 -0
- package/dist/game-servers.d.ts +530 -0
- package/dist/game-servers.js +244 -0
- package/dist/gills.d.ts +43 -0
- package/dist/gills.js +174 -0
- package/dist/git-commit.d.ts +143 -0
- package/dist/git-commit.js +251 -0
- package/dist/git-rpc.d.ts +310 -0
- package/dist/git-rpc.js +166 -0
- package/dist/git-steps.d.ts +579 -0
- package/dist/git-steps.js +804 -0
- package/dist/git-wire.d.ts +33 -0
- package/dist/git-wire.js +240 -0
- package/dist/git.d.ts +322 -0
- package/dist/git.js +98 -0
- package/dist/host.d.ts +97 -0
- package/dist/host.js +732 -0
- package/dist/inbox.d.ts +99 -0
- package/dist/inbox.js +184 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +15 -0
- package/dist/inference.d.ts +17 -0
- package/dist/inference.js +115 -0
- package/dist/internal/app-error.d.ts +8 -0
- package/dist/internal/app-error.js +36 -0
- package/dist/internal/app-session.d.ts +8 -0
- package/dist/internal/app-session.js +551 -0
- package/dist/internal/back-inputs.d.ts +22 -0
- package/dist/internal/back-inputs.js +93 -0
- package/dist/internal/browser-bridge.d.ts +30 -0
- package/dist/internal/browser-bridge.js +203 -0
- package/dist/internal/capabilities.d.ts +13 -0
- package/dist/internal/capabilities.js +138 -0
- package/dist/internal/commands.d.ts +9 -0
- package/dist/internal/commands.js +257 -0
- package/dist/internal/disconnect-host.d.ts +7 -0
- package/dist/internal/disconnect-host.js +19 -0
- package/dist/internal/git-edit-tree.d.ts +6 -0
- package/dist/internal/git-edit-tree.js +46 -0
- package/dist/internal/memory-fs.d.ts +39 -0
- package/dist/internal/memory-fs.js +154 -0
- package/dist/internal/protocol.d.ts +116 -0
- package/dist/internal/protocol.js +6 -0
- package/dist/internal/query-feed.d.ts +23 -0
- package/dist/internal/query-feed.js +111 -0
- package/dist/internal/result.d.ts +22 -0
- package/dist/internal/result.js +61 -0
- package/dist/internal/rpc-contract.d.ts +24 -0
- package/dist/internal/rpc-contract.js +78 -0
- package/dist/internal/schemas.d.ts +307 -0
- package/dist/internal/schemas.js +524 -0
- package/dist/internal/store.d.ts +8 -0
- package/dist/internal/store.js +30 -0
- package/dist/internal/terminal-gate.d.ts +17 -0
- package/dist/internal/terminal-gate.js +94 -0
- package/dist/lifecycle.d.ts +44 -0
- package/dist/lifecycle.js +1 -0
- package/dist/marketplace.d.ts +159 -0
- package/dist/marketplace.js +102 -0
- package/dist/media-json.d.ts +181 -0
- package/dist/media-json.js +204 -0
- package/dist/media-library.d.ts +11 -0
- package/dist/media-library.js +15 -0
- package/dist/media-request-id.d.ts +7 -0
- package/dist/media-request-id.js +16 -0
- package/dist/media.d.ts +354 -0
- package/dist/media.js +654 -0
- package/dist/method-refusal.d.ts +64 -0
- package/dist/method-refusal.js +48 -0
- package/dist/pending.d.ts +10 -0
- package/dist/pending.js +10 -0
- package/dist/query.d.ts +76 -0
- package/dist/query.js +195 -0
- package/dist/react-mount.d.ts +23 -0
- package/dist/react-mount.js +108 -0
- package/dist/react.d.ts +41 -0
- package/dist/react.js +111 -0
- package/dist/read-copy.d.ts +103 -0
- package/dist/read-copy.js +195 -0
- package/dist/roles/files.d.ts +295 -0
- package/dist/roles/files.js +184 -0
- package/dist/root.d.ts +21 -0
- package/dist/root.js +1 -0
- package/dist/rpc.d.ts +1 -0
- package/dist/rpc.js +1 -0
- package/dist/status.d.ts +17 -0
- package/dist/status.js +50 -0
- package/dist/storage-wire.d.ts +167 -0
- package/dist/storage-wire.js +115 -0
- package/dist/storage.d.ts +72 -0
- package/dist/storage.js +143 -0
- package/dist/store.d.ts +11 -0
- package/dist/store.js +1 -0
- package/dist/test-kit/git.d.ts +31 -0
- package/dist/test-kit/git.js +174 -0
- package/dist/ui.d.ts +169 -0
- package/dist/ui.js +10 -0
- package/dist/window.d.ts +41 -0
- package/dist/window.js +15 -0
- package/dist/world.d.ts +16 -0
- package/dist/world.js +17 -0
- package/docs/api/README.md +28 -0
- package/docs/api/app-build-contract.md +113 -0
- package/docs/api/backend-declaration.md +62 -0
- package/docs/api/backend-definition.md +215 -0
- package/docs/api/backend.md +269 -0
- package/docs/api/errors.md +169 -0
- package/docs/api/files.md +91 -0
- package/docs/api/gills.md +164 -0
- package/docs/api/git-commit.md +279 -0
- package/docs/api/git-rpc.md +243 -0
- package/docs/api/git-steps.md +1010 -0
- package/docs/api/git-wire.md +197 -0
- package/docs/api/git.md +579 -0
- package/docs/api/index.md +2880 -0
- package/docs/api/media-json.md +507 -0
- package/docs/api/media-request-id.md +32 -0
- package/docs/api/modules.md +32 -0
- package/docs/api/query.md +253 -0
- package/docs/api/react.md +216 -0
- package/docs/api/read-copy.md +204 -0
- package/docs/api/rpc.md +128 -0
- package/docs/api/storage.md +620 -0
- package/package.json +197 -3
package/dist/inbox.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type MemberInboxItem } from "@fungi.computer/puffball/inbox";
|
|
2
|
+
export { memberInboxItemSchema, memberInboxDeltaItemSchema, memberInboxSessionSchema, workflowReviewInboxItemSchema, workflowReviewKeySchema, memberInboxKey, memberInboxItemKey, type MemberInboxItem, type MemberInboxDeltaItem, type MemberInboxSession, type WorkflowReviewInboxItem, type WorkflowReviewKey, } from "@fungi.computer/puffball/inbox";
|
|
3
|
+
import type { AppAgentTransport } from "./agents.js";
|
|
4
|
+
import * as Schema from "effect/Schema";
|
|
5
|
+
import * as z from "zod";
|
|
6
|
+
/** A member Inbox page and its owner-issued continuation and revision. */
|
|
7
|
+
export declare const memberInboxPageSchema: Schema.Struct<{
|
|
8
|
+
readonly items: Schema.$Array<Schema.Union<readonly [Schema.Union<readonly [Schema.Struct<{
|
|
9
|
+
readonly agentId: Schema.String;
|
|
10
|
+
readonly sessionId: Schema.String;
|
|
11
|
+
readonly title: Schema.String;
|
|
12
|
+
readonly triggerId: Schema.optionalKey<Schema.String>;
|
|
13
|
+
readonly createdAt: Schema.Number;
|
|
14
|
+
readonly lastActivityAt: Schema.Number;
|
|
15
|
+
readonly settledAt: Schema.optionalKey<Schema.Number>;
|
|
16
|
+
readonly visitedAt: Schema.optionalKey<Schema.Number>;
|
|
17
|
+
readonly state: Schema.Literals<readonly ["needs_you", "running", "errored", "done"]>;
|
|
18
|
+
}>, Schema.Struct<{
|
|
19
|
+
readonly agentId: Schema.String;
|
|
20
|
+
readonly sessionId: Schema.String;
|
|
21
|
+
readonly state: Schema.Literal<"unavailable">;
|
|
22
|
+
}>]>, Schema.Struct<{
|
|
23
|
+
readonly kind: Schema.Literal<"workflow-review">;
|
|
24
|
+
readonly key: Schema.Struct<{
|
|
25
|
+
readonly runId: Schema.String;
|
|
26
|
+
readonly nodeId: Schema.String;
|
|
27
|
+
readonly iteration: Schema.String;
|
|
28
|
+
}>;
|
|
29
|
+
readonly installationId: Schema.String;
|
|
30
|
+
readonly workflowId: Schema.NullOr<Schema.String>;
|
|
31
|
+
readonly workflowTitle: Schema.String;
|
|
32
|
+
readonly reviewTitle: Schema.String;
|
|
33
|
+
readonly reviewers: Schema.Literals<readonly ["runner", "owners"]>;
|
|
34
|
+
readonly show: Schema.$Array<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
35
|
+
readonly choices: Schema.optionalKey<Schema.$Array<Schema.String>>;
|
|
36
|
+
readonly openedAt: Schema.Number;
|
|
37
|
+
readonly expiresAt: Schema.Number;
|
|
38
|
+
readonly state: Schema.Literals<readonly ["pending", "answered", "delivered", "timed_out", "closed"]>;
|
|
39
|
+
}>]>>;
|
|
40
|
+
readonly next: Schema.NullOr<Schema.String>;
|
|
41
|
+
readonly cursor: Schema.Number;
|
|
42
|
+
}>;
|
|
43
|
+
/** A successful visit to an existing admitted Inbox Session. */
|
|
44
|
+
export declare const inboxVisitResultSchema: z.ZodObject<{
|
|
45
|
+
visited: z.ZodLiteral<true>;
|
|
46
|
+
}, z.core.$strict>;
|
|
47
|
+
/** Pages the first read loads; later rows arrive as deltas. */
|
|
48
|
+
export declare const memberInboxInitialPages = 5;
|
|
49
|
+
/** Minimal EventSource surface, so a capability fetch can carry the stream. */
|
|
50
|
+
export type InboxEventSource = {
|
|
51
|
+
addEventListener(type: string, listener: (event: MessageEvent<string>) => void): void;
|
|
52
|
+
close(): void;
|
|
53
|
+
};
|
|
54
|
+
export type MemberInboxSnapshot = Readonly<{
|
|
55
|
+
items: readonly MemberInboxItem[];
|
|
56
|
+
status: "loading" | "live" | "error";
|
|
57
|
+
}>;
|
|
58
|
+
export type MemberInboxFeed = Readonly<{
|
|
59
|
+
/** Record that the member opened a Session; the owner moves its row. */
|
|
60
|
+
visit: (agentId: string, sessionId: string) => Promise<void>;
|
|
61
|
+
/** Re-register the current Agent directory and reload rows after a new Agent. */
|
|
62
|
+
refresh: () => Promise<void>;
|
|
63
|
+
close: () => void;
|
|
64
|
+
}>;
|
|
65
|
+
/**
|
|
66
|
+
* Load the member inbox, then follow its deltas. A delta that does not start
|
|
67
|
+
* at this client's cursor means one was missed: the stream is reopened from
|
|
68
|
+
* the cursor, and the owner replays every change after it. `reset` reloads.
|
|
69
|
+
*/
|
|
70
|
+
export declare function watchMemberInbox(options: Readonly<{
|
|
71
|
+
/** Base that serves `/inbox`, `/inbox/events` and `/inbox/visits`. */
|
|
72
|
+
baseUrl: string;
|
|
73
|
+
fetch: typeof globalThis.fetch;
|
|
74
|
+
openEvents: (url: string) => InboxEventSource;
|
|
75
|
+
onChange: (snapshot: MemberInboxSnapshot) => void;
|
|
76
|
+
}>): MemberInboxFeed;
|
|
77
|
+
/** Shared Team notices use the same member-admitted inbox transport as Session reads. */
|
|
78
|
+
export declare function readTeamInboxNoticePage(transport: Pick<AppAgentTransport, "baseUrl" | "fetch">, after?: string | null): Promise<{
|
|
79
|
+
readonly items: readonly ({
|
|
80
|
+
readonly appId: import("@fungi.computer/puffball").AppId;
|
|
81
|
+
readonly displayName: string;
|
|
82
|
+
readonly createdAt: number;
|
|
83
|
+
readonly dispositionId: string;
|
|
84
|
+
readonly releaseIds: readonly import("@fungi.computer/puffball").ReleaseId[];
|
|
85
|
+
readonly reason?: string | undefined;
|
|
86
|
+
} | {
|
|
87
|
+
readonly createdAt: number;
|
|
88
|
+
readonly kind: "seller-closed";
|
|
89
|
+
readonly dispositionId: string;
|
|
90
|
+
readonly sellerAccountId: string;
|
|
91
|
+
readonly buyerAccountId: string;
|
|
92
|
+
readonly appId: string;
|
|
93
|
+
readonly releaseIds: readonly [string];
|
|
94
|
+
readonly displayName: string;
|
|
95
|
+
readonly sellerName: string;
|
|
96
|
+
readonly requestId: string;
|
|
97
|
+
})[];
|
|
98
|
+
readonly next: string | null;
|
|
99
|
+
}>;
|
package/dist/inbox.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { memberInboxItemSchema, memberInboxDeltaItemSchema, memberInboxItemKey, } from "@fungi.computer/puffball/inbox";
|
|
2
|
+
export { memberInboxItemSchema, memberInboxDeltaItemSchema, memberInboxSessionSchema, workflowReviewInboxItemSchema, workflowReviewKeySchema, memberInboxKey, memberInboxItemKey, } from "@fungi.computer/puffball/inbox";
|
|
3
|
+
import { sellerClosureNoticeSchema } from "@fungi.computer/puffball/seller-closure-notice";
|
|
4
|
+
import { artifactDispositionNoticeSchema } from "@fungi.computer/puffball/artifact-dispositions";
|
|
5
|
+
import * as Schema from "effect/Schema";
|
|
6
|
+
import * as z from "zod";
|
|
7
|
+
import { reportCatchFailure } from "./failure.js";
|
|
8
|
+
/**
|
|
9
|
+
* Client for one member's inbox feed. The host's member owner decides nothing
|
|
10
|
+
* here either: this module keeps the rows it is sent, resumes from its member
|
|
11
|
+
* cursor, and re-reads whenever a delta could have been missed. It never
|
|
12
|
+
* polls.
|
|
13
|
+
*/
|
|
14
|
+
const time = Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isGreaterThanOrEqualTo(0)));
|
|
15
|
+
/** A member Inbox page and its owner-issued continuation and revision. */
|
|
16
|
+
export const memberInboxPageSchema = Schema.Struct({
|
|
17
|
+
items: Schema.Array(memberInboxItemSchema),
|
|
18
|
+
next: Schema.NullOr(Schema.String),
|
|
19
|
+
cursor: time,
|
|
20
|
+
});
|
|
21
|
+
/** A successful visit to an existing admitted Inbox Session. */
|
|
22
|
+
export const inboxVisitResultSchema = z.strictObject({
|
|
23
|
+
visited: z.literal(true),
|
|
24
|
+
});
|
|
25
|
+
const decodePage = Schema.decodeUnknownSync(memberInboxPageSchema);
|
|
26
|
+
const decodeRows = Schema.decodeUnknownSync(Schema.fromJsonString(Schema.Struct({
|
|
27
|
+
kind: Schema.Literal("rows"),
|
|
28
|
+
from: time,
|
|
29
|
+
to: time,
|
|
30
|
+
items: Schema.Array(memberInboxDeltaItemSchema),
|
|
31
|
+
more: Schema.Boolean,
|
|
32
|
+
})));
|
|
33
|
+
/** Pages the first read loads; later rows arrive as deltas. */
|
|
34
|
+
export const memberInboxInitialPages = 5;
|
|
35
|
+
/**
|
|
36
|
+
* Load the member inbox, then follow its deltas. A delta that does not start
|
|
37
|
+
* at this client's cursor means one was missed: the stream is reopened from
|
|
38
|
+
* the cursor, and the owner replays every change after it. `reset` reloads.
|
|
39
|
+
*/
|
|
40
|
+
export function watchMemberInbox(options) {
|
|
41
|
+
const items = new Map();
|
|
42
|
+
let cursor = 0;
|
|
43
|
+
let closed = false;
|
|
44
|
+
let events;
|
|
45
|
+
let generation = 0;
|
|
46
|
+
const emit = (status) => {
|
|
47
|
+
if (!closed)
|
|
48
|
+
options.onChange({ items: [...items.values()], status });
|
|
49
|
+
};
|
|
50
|
+
const upsert = (list) => {
|
|
51
|
+
for (const item of list) {
|
|
52
|
+
const key = memberInboxItemKey(item);
|
|
53
|
+
if ("deleted" in item)
|
|
54
|
+
items.delete(key);
|
|
55
|
+
else
|
|
56
|
+
items.set(key, item);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const follow = () => {
|
|
60
|
+
events?.close();
|
|
61
|
+
const current = ++generation;
|
|
62
|
+
const source = options.openEvents(`${options.baseUrl}/inbox/events?after=${String(cursor)}`);
|
|
63
|
+
events = source;
|
|
64
|
+
let disconnected = false;
|
|
65
|
+
source.addEventListener("error", () => {
|
|
66
|
+
if (closed || current !== generation)
|
|
67
|
+
return;
|
|
68
|
+
disconnected = true;
|
|
69
|
+
reportCatchFailure("inbox.observe", new Error("Member inbox stream disconnected"));
|
|
70
|
+
emit("error");
|
|
71
|
+
});
|
|
72
|
+
source.addEventListener("open", () => {
|
|
73
|
+
if (closed || current !== generation || !disconnected)
|
|
74
|
+
return;
|
|
75
|
+
// A transport reconnect is not an owner refresh. Read before claiming live.
|
|
76
|
+
void load();
|
|
77
|
+
});
|
|
78
|
+
source.addEventListener("rows", (event) => {
|
|
79
|
+
if (closed || current !== generation)
|
|
80
|
+
return;
|
|
81
|
+
let delta;
|
|
82
|
+
try {
|
|
83
|
+
delta = decodeRows(event.data);
|
|
84
|
+
}
|
|
85
|
+
catch (cause) {
|
|
86
|
+
reportCatchFailure("inbox.decode-event", cause);
|
|
87
|
+
emit("loading");
|
|
88
|
+
follow();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (delta.from !== cursor) {
|
|
92
|
+
// A missed delta: resume from what this client actually holds.
|
|
93
|
+
emit("loading");
|
|
94
|
+
follow();
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
upsert(delta.items);
|
|
98
|
+
cursor = delta.to;
|
|
99
|
+
emit("live");
|
|
100
|
+
});
|
|
101
|
+
source.addEventListener("reset", () => {
|
|
102
|
+
if (closed || current !== generation)
|
|
103
|
+
return;
|
|
104
|
+
void load();
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
const load = async () => {
|
|
108
|
+
const current = ++generation;
|
|
109
|
+
events?.close();
|
|
110
|
+
events = undefined;
|
|
111
|
+
emit("loading");
|
|
112
|
+
try {
|
|
113
|
+
items.clear();
|
|
114
|
+
let after = null;
|
|
115
|
+
let first = true;
|
|
116
|
+
for (let page = 0; page < memberInboxInitialPages; page += 1) {
|
|
117
|
+
const query = after === null ? "" : `?after=${encodeURIComponent(after)}`;
|
|
118
|
+
const response = await options.fetch(`${options.baseUrl}/inbox${query}`, {
|
|
119
|
+
cache: "no-store",
|
|
120
|
+
});
|
|
121
|
+
if (!response.ok)
|
|
122
|
+
throw new Error("Inbox unavailable");
|
|
123
|
+
const read = decodePage(await response.json());
|
|
124
|
+
if (closed || current !== generation)
|
|
125
|
+
return;
|
|
126
|
+
// Deltas resume after the first page's cursor; later pages only add.
|
|
127
|
+
if (first)
|
|
128
|
+
cursor = read.cursor;
|
|
129
|
+
first = false;
|
|
130
|
+
upsert(read.items);
|
|
131
|
+
after = read.next;
|
|
132
|
+
if (after === null)
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
emit("live");
|
|
136
|
+
follow();
|
|
137
|
+
}
|
|
138
|
+
catch (cause) {
|
|
139
|
+
if (closed || current !== generation)
|
|
140
|
+
return;
|
|
141
|
+
reportCatchFailure("inbox.refresh", cause);
|
|
142
|
+
emit("error");
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
void load();
|
|
146
|
+
return Object.freeze({
|
|
147
|
+
refresh: () => (closed ? Promise.resolve() : load()),
|
|
148
|
+
visit: async (agentId, sessionId) => {
|
|
149
|
+
const response = await options.fetch(`${options.baseUrl}/inbox/visits`, {
|
|
150
|
+
method: "POST",
|
|
151
|
+
headers: { "content-type": "application/json" },
|
|
152
|
+
body: JSON.stringify({ agentId, sessionId }),
|
|
153
|
+
});
|
|
154
|
+
if (!response.ok && response.status !== 404)
|
|
155
|
+
throw new Error("Visit was not recorded");
|
|
156
|
+
},
|
|
157
|
+
close: () => {
|
|
158
|
+
closed = true;
|
|
159
|
+
generation += 1;
|
|
160
|
+
events?.close();
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
const decodeTeamNotices = Schema.decodeUnknownSync(Schema.Struct({
|
|
165
|
+
items: Schema.Array(Schema.Union([
|
|
166
|
+
Schema.Struct({
|
|
167
|
+
...artifactDispositionNoticeSchema.fields,
|
|
168
|
+
reason: Schema.optional(artifactDispositionNoticeSchema.fields.reason),
|
|
169
|
+
createdAt: time,
|
|
170
|
+
}),
|
|
171
|
+
Schema.Struct({ ...sellerClosureNoticeSchema.fields, createdAt: time }),
|
|
172
|
+
])).pipe(Schema.check(Schema.isMaxLength(100))),
|
|
173
|
+
next: Schema.NullOr(Schema.String.pipe(Schema.check(Schema.isMaxLength(1024)))),
|
|
174
|
+
}), { onExcessProperty: "error" });
|
|
175
|
+
/** Shared Team notices use the same member-admitted inbox transport as Session reads. */
|
|
176
|
+
export async function readTeamInboxNoticePage(transport, after = null) {
|
|
177
|
+
const url = new URL(`${transport.baseUrl}/inbox/notices`);
|
|
178
|
+
if (after !== null)
|
|
179
|
+
url.searchParams.set("after", after);
|
|
180
|
+
const response = await transport.fetch(url);
|
|
181
|
+
if (!response.ok)
|
|
182
|
+
throw new Error("Team notices unavailable");
|
|
183
|
+
return decodeTeamNotices(await response.json());
|
|
184
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export { FungiAuthorSchema, FungiDelegationReplySchema, FungiMessageMetaSchema, messageAuthor, messageDelegationReply, authorMeta, } from "./agent-message-meta.js";
|
|
2
|
+
export type { FungiAuthor, FungiDelegationReply, FungiMessageMeta, MessageMetaValue, AuthorMeta, } from "./agent-message-meta.js";
|
|
3
|
+
export { createCapabilityRegistry, defineCapability } from "./capabilities.js";
|
|
4
|
+
export { pending, pendingSchema } from "./pending.js";
|
|
5
|
+
export type { Pending } from "./pending.js";
|
|
6
|
+
export type { CapabilityContract, CapabilityDirectory, CapabilityRegistry, } from "./capabilities.js";
|
|
7
|
+
export { agentList, agentManage, agentRename, agentSessionRead, agentSessionWrite, agentToolPolicy, createAppAgent, renameAppAgent, appAgentCreateInputSchema, appAgentRenameInputSchema, appAgentSchema, appAgentToolPolicyResultSchema, appAgentToolPolicyStatusSchema, listAppAgents, openAppAgent, } from "./agents.js";
|
|
8
|
+
export type { AppAgent, AppAgentCreateHandle, AppAgentCreateInput, AppAgentDirectoryHandle, AppAgentListHandle, AppAgentRenameHandle, AppAgentRenameInput, AppAgentToolPolicyHandle, AppAgentToolPolicyResult, AppAgentToolPolicyStatus, AppAgentTransport, AppAgentTransportHandle, } from "./agents.js";
|
|
9
|
+
export { mediaGeneration, mediaGenerationFailureSchema, mediaGenerationReferenceSchema, mediaGenerationSelectionSchema, mediaModelSchema, openMediaGeneration, } from "./media.js";
|
|
10
|
+
export type { MediaGenerationHandle, MediaGenerationAttempt, MediaGenerationAttemptHandle, MediaGenerationFailure, MediaGenerationInput, MediaGenerationOutcome, MediaGenerationReference, MediaGenerationResult, MediaGenerationSelection, MediaModel, MediaOutputFormat, MediaGenerationSession, } from "./media.js";
|
|
11
|
+
export type { AppCommand, AppCommandHandler, AppCommandInvocation, AppCommands, } from "./commands.js";
|
|
12
|
+
export { registerCatalog } from "./commands.js";
|
|
13
|
+
export { connectApp } from "./connect.js";
|
|
14
|
+
export type { ConnectAppOptions } from "./connect.js";
|
|
15
|
+
/** Data exchanged by iframe and host before the RPC MessagePort takes over. */
|
|
16
|
+
export { APP_CONNECT_TYPE, APP_PROTOCOL_VERSION, APP_READY_TYPE, } from "./internal/protocol.js";
|
|
17
|
+
export type { AppConnectMessage, AppReadyMessage, } from "./internal/protocol.js";
|
|
18
|
+
export { AppError } from "./errors.js";
|
|
19
|
+
export { statusActionAllowed, statusText } from "./status.js";
|
|
20
|
+
export { APP_BROWSER_SAVE_MAX_BYTES, APP_BROWSER_COPY_MAX_BYTES, APP_STATUS_ITEMS_MAX, APP_STATUS_OPTIONS_MAX, APP_STATUS_TEXT_MAX, } from "./ui.js";
|
|
21
|
+
export { parseStatusAction as parseAppStatusAction, parseStatusItems as parseAppStatusItems, } from "./internal/schemas.js";
|
|
22
|
+
export type { AppErrorCode, AppErrorOptions } from "./errors.js";
|
|
23
|
+
export type { AppContext, AppIdentity, AppOpenRequest, AppLifecycle, FocusState, } from "./lifecycle.js";
|
|
24
|
+
export type { AppRoot } from "./root.js";
|
|
25
|
+
export type { AgentSessionSelection } from "./ui.js";
|
|
26
|
+
export type { Disposer, ReadonlyStore } from "./store.js";
|
|
27
|
+
export type { AppBrowserAction, AppBrowserActionOutcome, AppBrowserActionRefusal, AgentAccessOperation, AppPermissionOutcome, AppPermissionRequest, AppStatusAction, AppStatusActionHandler, AppStatusIcon, AppStatusItem, AppStatusOption, AppStatusTone, ComputerAccessOperation, FileNavigationInput, HostUi, ToastInput, } from "./ui.js";
|
|
28
|
+
export { APP_NAVIGATION_CONTRACT_VERSION, APP_NAVIGATION_TITLE_MAX, inertHostNavigation, } from "./window.js";
|
|
29
|
+
export type { AppBackHandler, AppNavigationState, AppWindow, BeforeAppClose, HostNavigation, } from "./window.js";
|
|
30
|
+
export { appStorage, AppStorageError } from "./storage.js";
|
|
31
|
+
export type { AppStorage, AppStorageWatch, AppStorageWrite, AppStorageReset, ResolvedAppStorage, } from "./storage.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { FungiAuthorSchema, FungiDelegationReplySchema, FungiMessageMetaSchema, messageAuthor, messageDelegationReply, authorMeta, } from "./agent-message-meta.js";
|
|
2
|
+
export { createCapabilityRegistry, defineCapability } from "./capabilities.js";
|
|
3
|
+
export { pending, pendingSchema } from "./pending.js";
|
|
4
|
+
export { agentList, agentManage, agentRename, agentSessionRead, agentSessionWrite, agentToolPolicy, createAppAgent, renameAppAgent, appAgentCreateInputSchema, appAgentRenameInputSchema, appAgentSchema, appAgentToolPolicyResultSchema, appAgentToolPolicyStatusSchema, listAppAgents, openAppAgent, } from "./agents.js";
|
|
5
|
+
export { mediaGeneration, mediaGenerationFailureSchema, mediaGenerationReferenceSchema, mediaGenerationSelectionSchema, mediaModelSchema, openMediaGeneration, } from "./media.js";
|
|
6
|
+
export { registerCatalog } from "./commands.js";
|
|
7
|
+
export { connectApp } from "./connect.js";
|
|
8
|
+
/** Data exchanged by iframe and host before the RPC MessagePort takes over. */
|
|
9
|
+
export { APP_CONNECT_TYPE, APP_PROTOCOL_VERSION, APP_READY_TYPE, } from "./internal/protocol.js";
|
|
10
|
+
export { AppError } from "./errors.js";
|
|
11
|
+
export { statusActionAllowed, statusText } from "./status.js";
|
|
12
|
+
export { APP_BROWSER_SAVE_MAX_BYTES, APP_BROWSER_COPY_MAX_BYTES, APP_STATUS_ITEMS_MAX, APP_STATUS_OPTIONS_MAX, APP_STATUS_TEXT_MAX, } from "./ui.js";
|
|
13
|
+
export { parseStatusAction as parseAppStatusAction, parseStatusItems as parseAppStatusItems, } from "./internal/schemas.js";
|
|
14
|
+
export { APP_NAVIGATION_CONTRACT_VERSION, APP_NAVIGATION_TITLE_MAX, inertHostNavigation, } from "./window.js";
|
|
15
|
+
export { appStorage, AppStorageError } from "./storage.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CapabilityContract, CapabilityDirectory } from "./capabilities.js";
|
|
2
|
+
/** One request lifetime. Closing it cancels only this generation, not other calls. */
|
|
3
|
+
export type AppInferenceRequest = {
|
|
4
|
+
fetch(request: Request): Promise<Response>;
|
|
5
|
+
close(): Promise<void>;
|
|
6
|
+
[Symbol.dispose](): void;
|
|
7
|
+
};
|
|
8
|
+
/** Live generation capability supplied by the host. */
|
|
9
|
+
export type AppInferenceHandle = {
|
|
10
|
+
open(): Promise<AppInferenceRequest>;
|
|
11
|
+
};
|
|
12
|
+
export declare const llmGeneration: CapabilityContract<AppInferenceHandle>;
|
|
13
|
+
/** OpenAI-compatible transport; no Agent, Session, host URL or credentials are exposed. */
|
|
14
|
+
export declare function createAppInferenceTransport(capabilities: CapabilityDirectory): {
|
|
15
|
+
baseURL: string;
|
|
16
|
+
fetch: typeof globalThis.fetch;
|
|
17
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { defineCapability } from "./capabilities.js";
|
|
2
|
+
import { rpcFetchHandleSchema, rpcHandleSchema, rpcMethod, } from "./internal/rpc-contract.js";
|
|
3
|
+
import * as Schema from "effect/Schema";
|
|
4
|
+
import { AppError } from "./errors.js";
|
|
5
|
+
import { reportCatchFailure } from "./failure.js";
|
|
6
|
+
export const llmGeneration = defineCapability("llm.generation", 1, rpcHandleSchema({ open: rpcMethod(rpcFetchHandleSchema) }));
|
|
7
|
+
const baseURL = "https://inference.fungi.invalid/v1";
|
|
8
|
+
const decodeResponse = Schema.decodeUnknownSync(Schema.instanceOf(Response));
|
|
9
|
+
/** OpenAI-compatible transport; no Agent, Session, host URL or credentials are exposed. */
|
|
10
|
+
export function createAppInferenceTransport(capabilities) {
|
|
11
|
+
const fetch = async (input, init) => {
|
|
12
|
+
const request = new Request(input, init);
|
|
13
|
+
const url = new URL(request.url);
|
|
14
|
+
if (url.origin !== "https://inference.fungi.invalid" ||
|
|
15
|
+
url.search !== "" ||
|
|
16
|
+
!((request.method === "GET" && url.pathname === "/v1/models") ||
|
|
17
|
+
(request.method === "POST" && url.pathname === "/v1/chat/completions")))
|
|
18
|
+
throw new AppError("The inference request target is invalid", {
|
|
19
|
+
code: "INVALID_ARGUMENT",
|
|
20
|
+
retryable: false,
|
|
21
|
+
});
|
|
22
|
+
request.signal.throwIfAborted();
|
|
23
|
+
let handle;
|
|
24
|
+
let closed = false;
|
|
25
|
+
let closing;
|
|
26
|
+
const close = () => {
|
|
27
|
+
closed = true;
|
|
28
|
+
if (closing !== undefined)
|
|
29
|
+
return closing;
|
|
30
|
+
request.signal.removeEventListener("abort", abort);
|
|
31
|
+
const opened = handle;
|
|
32
|
+
if (opened === undefined)
|
|
33
|
+
return Promise.resolve();
|
|
34
|
+
closing = (async () => {
|
|
35
|
+
try {
|
|
36
|
+
await opened.close();
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
opened[Symbol.dispose]();
|
|
40
|
+
}
|
|
41
|
+
})();
|
|
42
|
+
return closing;
|
|
43
|
+
};
|
|
44
|
+
// Cap'n Web carries Request/Response streams but not Request.signal. The
|
|
45
|
+
// per-request object lifetime supplies cancellation across that boundary.
|
|
46
|
+
let rejectAbort = () => undefined;
|
|
47
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
48
|
+
rejectAbort = reject;
|
|
49
|
+
});
|
|
50
|
+
const abort = () => {
|
|
51
|
+
void close().catch((cause) => {
|
|
52
|
+
reportCatchFailure("inference.abort-close", cause);
|
|
53
|
+
});
|
|
54
|
+
rejectAbort(new DOMException("The operation was aborted", "AbortError"));
|
|
55
|
+
};
|
|
56
|
+
request.signal.addEventListener("abort", abort, { once: true });
|
|
57
|
+
try {
|
|
58
|
+
if (request.signal.aborted)
|
|
59
|
+
abort();
|
|
60
|
+
const opening = capabilities
|
|
61
|
+
.require(llmGeneration)
|
|
62
|
+
.open()
|
|
63
|
+
.then(async (opened) => {
|
|
64
|
+
handle = opened;
|
|
65
|
+
if (closed) {
|
|
66
|
+
await close();
|
|
67
|
+
request.signal.throwIfAborted();
|
|
68
|
+
throw new Error("Inference request is closed");
|
|
69
|
+
}
|
|
70
|
+
return opened;
|
|
71
|
+
});
|
|
72
|
+
const opened = await Promise.race([opening, aborted]);
|
|
73
|
+
const response = decodeResponse(await Promise.race([opened.fetch(request), aborted]));
|
|
74
|
+
request.signal.throwIfAborted();
|
|
75
|
+
if (response.body === null) {
|
|
76
|
+
await close();
|
|
77
|
+
return response;
|
|
78
|
+
}
|
|
79
|
+
const reader = response.body.getReader();
|
|
80
|
+
const body = new ReadableStream({
|
|
81
|
+
async pull(controller) {
|
|
82
|
+
try {
|
|
83
|
+
const next = await Promise.race([reader.read(), aborted]);
|
|
84
|
+
if (next.done) {
|
|
85
|
+
controller.close();
|
|
86
|
+
await close();
|
|
87
|
+
}
|
|
88
|
+
else
|
|
89
|
+
controller.enqueue(next.value);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
controller.error(request.signal.aborted ? request.signal.reason : error);
|
|
93
|
+
await close();
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
async cancel(reason) {
|
|
97
|
+
await Promise.all([reader.cancel(reason), close()]);
|
|
98
|
+
},
|
|
99
|
+
}, { highWaterMark: 0 });
|
|
100
|
+
return new Response(body, {
|
|
101
|
+
status: response.status,
|
|
102
|
+
statusText: response.statusText,
|
|
103
|
+
headers: response.headers,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
await close().catch((cause) => {
|
|
108
|
+
reportCatchFailure("inference.request-cleanup", cause);
|
|
109
|
+
});
|
|
110
|
+
request.signal.throwIfAborted();
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
return { baseURL, fetch };
|
|
115
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AppError, type AppErrorCode } from "../errors.js";
|
|
2
|
+
export type AppErrorData = {
|
|
3
|
+
readonly code: AppErrorCode;
|
|
4
|
+
readonly message: string;
|
|
5
|
+
readonly retryable: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function appErrorData(cause: unknown): AppErrorData;
|
|
8
|
+
export declare function appErrorFromData(value: AppErrorData): AppError;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { AppError } from "../errors.js";
|
|
2
|
+
import { parseErrorData } from "./schemas.js";
|
|
3
|
+
export function appErrorData(cause) {
|
|
4
|
+
if (cause instanceof AppError) {
|
|
5
|
+
return {
|
|
6
|
+
code: cause.code,
|
|
7
|
+
message: bounded(cause.message),
|
|
8
|
+
retryable: cause.retryable,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
code: "HOST_FAILURE",
|
|
13
|
+
message: "Host operation failed",
|
|
14
|
+
retryable: false,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function appErrorFromData(value) {
|
|
18
|
+
try {
|
|
19
|
+
const parsed = parseErrorData(value);
|
|
20
|
+
return new AppError(parsed.message, {
|
|
21
|
+
code: parsed.code,
|
|
22
|
+
retryable: parsed.retryable,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
catch (cause) {
|
|
26
|
+
return new AppError("The host returned a malformed error", {
|
|
27
|
+
cause,
|
|
28
|
+
code: "PROTOCOL",
|
|
29
|
+
retryable: false,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function bounded(message) {
|
|
34
|
+
const clean = message.trim().slice(0, 512);
|
|
35
|
+
return clean || "Host operation failed";
|
|
36
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AppRoot } from "../root.js";
|
|
2
|
+
export declare function connectAppPort(options: {
|
|
3
|
+
readonly epoch: string;
|
|
4
|
+
readonly isActive: () => boolean;
|
|
5
|
+
readonly onDisposed: () => void;
|
|
6
|
+
readonly port: MessagePort;
|
|
7
|
+
readonly window: Window;
|
|
8
|
+
}): Promise<AppRoot>;
|