@fungi.computer/agar 0.1.0 → 0.2.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/dist/agent-message-meta.d.ts +15 -15
- package/dist/agent-message-meta.js +5 -5
- package/dist/agents.d.ts +86 -13
- package/dist/agents.js +48 -25
- package/dist/apps.js +4 -4
- package/dist/backend-definition.d.ts +41 -4
- package/dist/backend-definition.js +70 -10
- package/dist/backend.js +4 -4
- package/dist/channels.js +4 -4
- package/dist/computer-contracts.d.ts +15 -15
- package/dist/computer-contracts.js +14 -14
- package/dist/computer.js +16 -16
- package/dist/game-servers.js +2 -2
- package/dist/git-rpc.d.ts +23 -23
- package/dist/git-rpc.js +14 -16
- package/dist/git.d.ts +9 -9
- package/dist/git.js +8 -8
- package/dist/host.d.ts +3 -1
- package/dist/host.js +5 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +3 -2
- package/dist/inference.js +2 -1
- package/dist/internal/app-session.js +37 -1
- package/dist/internal/protocol.d.ts +4 -4
- package/dist/internal/schemas.d.ts +33 -7
- package/dist/internal/schemas.js +107 -16
- package/dist/marketplace.js +7 -5
- package/dist/media-request-id.d.ts +1 -1
- package/dist/media-request-id.js +2 -2
- package/dist/media.js +2 -2
- package/dist/method-presentation.d.ts +7 -0
- package/dist/method-presentation.js +14 -0
- package/dist/method-refusal.d.ts +5 -5
- package/dist/method-refusal.js +4 -4
- package/dist/react.d.ts +14 -2
- package/dist/react.js +40 -4
- package/dist/read-copy.d.ts +1 -1
- package/dist/read-copy.js +3 -6
- package/dist/storage.js +1 -1
- package/dist/test-kit/git.js +19 -2
- package/dist/window.d.ts +64 -0
- package/dist/window.js +31 -0
- package/docs/api/backend-definition.md +83 -9
- package/docs/api/backend.md +44 -38
- package/docs/api/git-rpc.md +35 -35
- package/docs/api/git.md +66 -80
- package/docs/api/index.md +775 -128
- package/docs/api/media-request-id.md +1 -1
- package/docs/api/method-presentation.md +21 -0
- package/docs/api/modules.md +1 -0
- package/docs/api/react.md +10 -4
- package/package.json +10 -5
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
/** Who a Session line came from, as the admitting host authenticated them. */
|
|
3
|
-
export declare const FungiAuthorSchema: z.ZodObject<{
|
|
3
|
+
export declare const FungiAuthorSchema: z.ZodLazy<z.ZodObject<{
|
|
4
4
|
id: z.ZodString;
|
|
5
5
|
name: z.ZodString;
|
|
6
|
-
}, z.core.$strict
|
|
6
|
+
}, z.core.$strict>>;
|
|
7
7
|
/** Who a Session line came from, as the admitting host authenticated them. */
|
|
8
8
|
export type FungiAuthor = z.infer<typeof FungiAuthorSchema>;
|
|
9
9
|
/**
|
|
@@ -11,10 +11,10 @@ export type FungiAuthor = z.infer<typeof FungiAuthorSchema>;
|
|
|
11
11
|
* mail it sent. `commandId` is the replying Session's accepted command, the
|
|
12
12
|
* same id as the sender's `agents.send` receipt.
|
|
13
13
|
*/
|
|
14
|
-
export declare const FungiDelegationReplySchema: z.ZodObject<{
|
|
15
|
-
agentId: z.ZodString
|
|
16
|
-
sessionId: z.ZodString
|
|
17
|
-
commandId: z.ZodString
|
|
14
|
+
export declare const FungiDelegationReplySchema: z.ZodLazy<z.ZodObject<{
|
|
15
|
+
agentId: z.ZodLazy<z.ZodString>;
|
|
16
|
+
sessionId: z.ZodLazy<z.ZodString>;
|
|
17
|
+
commandId: z.ZodLazy<z.ZodString>;
|
|
18
18
|
outcome: z.ZodEnum<{
|
|
19
19
|
completed: "completed";
|
|
20
20
|
failed: "failed";
|
|
@@ -23,7 +23,7 @@ export declare const FungiDelegationReplySchema: z.ZodObject<{
|
|
|
23
23
|
outcome_unknown: "outcome_unknown";
|
|
24
24
|
}>;
|
|
25
25
|
diagnostic: z.ZodOptional<z.ZodString>;
|
|
26
|
-
}, z.core.$strict
|
|
26
|
+
}, z.core.$strict>>;
|
|
27
27
|
/** A delegated Agent's reply as the admitting host authenticated it. */
|
|
28
28
|
export type FungiDelegationReply = z.infer<typeof FungiDelegationReplySchema>;
|
|
29
29
|
/**
|
|
@@ -31,17 +31,17 @@ export type FungiDelegationReply = z.infer<typeof FungiDelegationReplySchema>;
|
|
|
31
31
|
* Shiitake stores it opaquely; the host writes it and Apps read it.
|
|
32
32
|
*/
|
|
33
33
|
export declare const FungiMessageMetaSchema: z.ZodObject<{
|
|
34
|
-
author: z.ZodOptional<z.ZodObject<{
|
|
34
|
+
author: z.ZodOptional<z.ZodLazy<z.ZodObject<{
|
|
35
35
|
id: z.ZodString;
|
|
36
36
|
name: z.ZodString;
|
|
37
|
-
}, z.core.$strict
|
|
37
|
+
}, z.core.$strict>>>;
|
|
38
38
|
delegation: z.ZodOptional<z.ZodObject<{
|
|
39
|
-
ancestors: z.ZodArray<z.ZodString
|
|
39
|
+
ancestors: z.ZodArray<z.ZodLazy<z.ZodString>>;
|
|
40
40
|
maxDepth: z.ZodNumber;
|
|
41
|
-
reply: z.ZodOptional<z.ZodObject<{
|
|
42
|
-
agentId: z.ZodString
|
|
43
|
-
sessionId: z.ZodString
|
|
44
|
-
commandId: z.ZodString
|
|
41
|
+
reply: z.ZodOptional<z.ZodLazy<z.ZodObject<{
|
|
42
|
+
agentId: z.ZodLazy<z.ZodString>;
|
|
43
|
+
sessionId: z.ZodLazy<z.ZodString>;
|
|
44
|
+
commandId: z.ZodLazy<z.ZodString>;
|
|
45
45
|
outcome: z.ZodEnum<{
|
|
46
46
|
completed: "completed";
|
|
47
47
|
failed: "failed";
|
|
@@ -50,7 +50,7 @@ export declare const FungiMessageMetaSchema: z.ZodObject<{
|
|
|
50
50
|
outcome_unknown: "outcome_unknown";
|
|
51
51
|
}>;
|
|
52
52
|
diagnostic: z.ZodOptional<z.ZodString>;
|
|
53
|
-
}, z.core.$strict
|
|
53
|
+
}, z.core.$strict>>>;
|
|
54
54
|
}, z.core.$strict>>;
|
|
55
55
|
}, z.core.$strict>;
|
|
56
56
|
/** The metadata the host attaches to every prompt and operator line it admits. */
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
/** Who a Session line came from, as the admitting host authenticated them. */
|
|
3
|
-
export const FungiAuthorSchema = z.strictObject({
|
|
3
|
+
export const FungiAuthorSchema = z.lazy(() => z.strictObject({
|
|
4
4
|
id: z.string().min(1).max(256),
|
|
5
5
|
name: z.string().min(1).max(128),
|
|
6
|
-
});
|
|
7
|
-
const identifier = z.string().min(1).max(256);
|
|
6
|
+
}));
|
|
7
|
+
const identifier = z.lazy(() => z.string().min(1).max(256));
|
|
8
8
|
/**
|
|
9
9
|
* A delegated Agent's reply as the admitting host authenticated it against the
|
|
10
10
|
* mail it sent. `commandId` is the replying Session's accepted command, the
|
|
11
11
|
* same id as the sender's `agents.send` receipt.
|
|
12
12
|
*/
|
|
13
|
-
export const FungiDelegationReplySchema = z.strictObject({
|
|
13
|
+
export const FungiDelegationReplySchema = z.lazy(() => z.strictObject({
|
|
14
14
|
agentId: identifier,
|
|
15
15
|
sessionId: identifier,
|
|
16
16
|
commandId: identifier,
|
|
@@ -24,7 +24,7 @@ export const FungiDelegationReplySchema = z.strictObject({
|
|
|
24
24
|
]),
|
|
25
25
|
/** Bounded, single-line terminal diagnostic for work that did not complete. */
|
|
26
26
|
diagnostic: z.string().min(1).max(200).optional(),
|
|
27
|
-
});
|
|
27
|
+
}));
|
|
28
28
|
/**
|
|
29
29
|
* The metadata the host attaches to every prompt and operator line it admits.
|
|
30
30
|
* Shiitake stores it opaquely; the host writes it and Apps read it.
|
package/dist/agents.d.ts
CHANGED
|
@@ -4,13 +4,44 @@ import * as z from "zod";
|
|
|
4
4
|
import * as Schema from "effect/Schema";
|
|
5
5
|
import type { CapabilityContract, CapabilityDirectory } from "./capabilities.js";
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
|
|
7
|
+
* An Agent's avatar: Sprite's Avatar v1 envelope. Apps check its shape; the
|
|
8
|
+
* host owns the character-catalog refinement when it stores one.
|
|
9
|
+
*/
|
|
10
|
+
export declare const appAgentAvatarSchema: Schema.declare<{
|
|
11
|
+
v: 1;
|
|
12
|
+
character: "mushroom" | "cat" | "burger";
|
|
13
|
+
appearance: Record<string, string | number | boolean>;
|
|
14
|
+
expression: string;
|
|
15
|
+
renderStyle: "plain" | "pencil" | "manga" | "riso" | "halftone" | "blueprint" | "crt" | "watercolor";
|
|
16
|
+
}, {
|
|
17
|
+
v: 1;
|
|
18
|
+
character: "mushroom" | "cat" | "burger";
|
|
19
|
+
appearance: Record<string, string | number | boolean>;
|
|
20
|
+
expression: string;
|
|
21
|
+
renderStyle: "plain" | "pencil" | "manga" | "riso" | "halftone" | "blueprint" | "crt" | "watercolor";
|
|
22
|
+
}>;
|
|
23
|
+
/**
|
|
24
|
+
* Validates the wire shape of an Agent record: its id, display name, avatar,
|
|
25
|
+
* and which session operations (read, send, manage) this App may perform on
|
|
26
|
+
* it. Every Agent has an avatar: the one its owner chose, else Sprite's
|
|
27
|
+
* `seededAvatar(agentId)`. Conversations carry none of their own.
|
|
10
28
|
*/
|
|
11
29
|
export declare const appAgentSchema: Schema.Struct<{
|
|
12
30
|
readonly agentId: Schema.String;
|
|
13
31
|
readonly name: Schema.String;
|
|
32
|
+
readonly avatar: Schema.declare<{
|
|
33
|
+
v: 1;
|
|
34
|
+
character: "mushroom" | "cat" | "burger";
|
|
35
|
+
appearance: Record<string, string | number | boolean>;
|
|
36
|
+
expression: string;
|
|
37
|
+
renderStyle: "plain" | "pencil" | "manga" | "riso" | "halftone" | "blueprint" | "crt" | "watercolor";
|
|
38
|
+
}, {
|
|
39
|
+
v: 1;
|
|
40
|
+
character: "mushroom" | "cat" | "burger";
|
|
41
|
+
appearance: Record<string, string | number | boolean>;
|
|
42
|
+
expression: string;
|
|
43
|
+
renderStyle: "plain" | "pencil" | "manga" | "riso" | "halftone" | "blueprint" | "crt" | "watercolor";
|
|
44
|
+
}>;
|
|
14
45
|
readonly sessionOperations: Schema.$Array<Schema.Literals<readonly ["agent.read", "agent.send", "agent.manage"]>>;
|
|
15
46
|
}>;
|
|
16
47
|
/**
|
|
@@ -19,24 +50,38 @@ export declare const appAgentSchema: Schema.Struct<{
|
|
|
19
50
|
*/
|
|
20
51
|
export type AppAgent = Schema.Schema.Type<typeof appAgentSchema>;
|
|
21
52
|
/** The admitted AGENTS.list projection, containing only ids and display names. */
|
|
22
|
-
export declare const appAgentListResultSchema: z.ZodObject<{
|
|
53
|
+
export declare const appAgentListResultSchema: z.ZodLazy<z.ZodObject<{
|
|
23
54
|
agents: z.ZodArray<z.ZodObject<{
|
|
24
55
|
agentId: z.ZodString;
|
|
25
56
|
name: z.ZodString;
|
|
26
57
|
}, z.core.$strict>>;
|
|
27
|
-
}, z.core.$strict
|
|
58
|
+
}, z.core.$strict>>;
|
|
28
59
|
/** Computer provisioning is a Team creation choice, separate from Home policy. */
|
|
29
60
|
export declare const appAgentComputerSchema: Schema.Literals<readonly ["new", "none"]>;
|
|
30
|
-
/** Validates Agent creation input: a name, a caller-chosen request id
|
|
31
|
-
* optional Computer provisioning choice. */
|
|
61
|
+
/** Validates Agent creation input: a name, a caller-chosen request id, an
|
|
62
|
+
* optional Computer provisioning choice and an optional chosen avatar. */
|
|
32
63
|
export declare const appAgentCreateInputSchema: Schema.Struct<{
|
|
33
64
|
readonly name: Schema.String;
|
|
34
65
|
readonly requestId: Schema.String;
|
|
35
66
|
readonly computer: Schema.optionalKey<Schema.Literals<readonly ["new", "none"]>>;
|
|
67
|
+
readonly avatar: Schema.optionalKey<Schema.declare<{
|
|
68
|
+
v: 1;
|
|
69
|
+
character: "mushroom" | "cat" | "burger";
|
|
70
|
+
appearance: Record<string, string | number | boolean>;
|
|
71
|
+
expression: string;
|
|
72
|
+
renderStyle: "plain" | "pencil" | "manga" | "riso" | "halftone" | "blueprint" | "crt" | "watercolor";
|
|
73
|
+
}, {
|
|
74
|
+
v: 1;
|
|
75
|
+
character: "mushroom" | "cat" | "burger";
|
|
76
|
+
appearance: Record<string, string | number | boolean>;
|
|
77
|
+
expression: string;
|
|
78
|
+
renderStyle: "plain" | "pencil" | "manga" | "riso" | "halftone" | "blueprint" | "crt" | "watercolor";
|
|
79
|
+
}>>;
|
|
36
80
|
}>;
|
|
37
81
|
/**
|
|
38
82
|
* Input for creating a new Agent: its name, a caller-chosen request id
|
|
39
|
-
* for idempotency,
|
|
83
|
+
* for idempotency, whether to provision a new Computer for it, and the
|
|
84
|
+
* avatar it wears (omitted, it wears its seeded avatar).
|
|
40
85
|
*/
|
|
41
86
|
export type AppAgentCreateInput = Readonly<Schema.Schema.Type<typeof appAgentCreateInputSchema>>;
|
|
42
87
|
/** Live object-capability shape received from Cap'n Web. */
|
|
@@ -93,26 +138,54 @@ export type AppAgentRenameHandle = {
|
|
|
93
138
|
export declare const agentRename: CapabilityContract<AppAgentRenameHandle>;
|
|
94
139
|
/** Rename an Agent through the host-granted owner-only capability. */
|
|
95
140
|
export declare function renameAppAgent(capabilities: CapabilityDirectory, input: AppAgentRenameInput): Promise<AppAgent>;
|
|
141
|
+
/** Validates avatar input: the target Agent and the avatar it now wears. */
|
|
142
|
+
export declare const appAgentAvatarInputSchema: Schema.Struct<{
|
|
143
|
+
readonly agentId: Schema.String;
|
|
144
|
+
readonly avatar: Schema.declare<{
|
|
145
|
+
v: 1;
|
|
146
|
+
character: "mushroom" | "cat" | "burger";
|
|
147
|
+
appearance: Record<string, string | number | boolean>;
|
|
148
|
+
expression: string;
|
|
149
|
+
renderStyle: "plain" | "pencil" | "manga" | "riso" | "halftone" | "blueprint" | "crt" | "watercolor";
|
|
150
|
+
}, {
|
|
151
|
+
v: 1;
|
|
152
|
+
character: "mushroom" | "cat" | "burger";
|
|
153
|
+
appearance: Record<string, string | number | boolean>;
|
|
154
|
+
expression: string;
|
|
155
|
+
renderStyle: "plain" | "pencil" | "manga" | "riso" | "halftone" | "blueprint" | "crt" | "watercolor";
|
|
156
|
+
}>;
|
|
157
|
+
}>;
|
|
158
|
+
/** Input for changing an existing Agent's avatar. */
|
|
159
|
+
export type AppAgentAvatarInput = Readonly<Schema.Schema.Type<typeof appAgentAvatarInputSchema>>;
|
|
160
|
+
/** Capability handle for changing an Agent's avatar. */
|
|
161
|
+
export type AppAgentAvatarHandle = {
|
|
162
|
+
/** Set an existing Agent's avatar and return its updated record. */
|
|
163
|
+
setAvatar(input: AppAgentAvatarInput): Promise<AppAgent>;
|
|
164
|
+
};
|
|
165
|
+
/** Owner-only capability to change an existing Agent's avatar; not every host grants it. */
|
|
166
|
+
export declare const agentAvatar: CapabilityContract<AppAgentAvatarHandle>;
|
|
167
|
+
/** Change an Agent's avatar through the host-granted owner-only capability. */
|
|
168
|
+
export declare function setAppAgentAvatar(capabilities: CapabilityDirectory, input: AppAgentAvatarInput): Promise<AppAgent>;
|
|
96
169
|
/** One Agent's App-tool policy, as the owner-only policy capability reports it. */
|
|
97
|
-
export declare const appAgentToolPolicyStatusSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
170
|
+
export declare const appAgentToolPolicyStatusSchema: z.ZodLazy<z.ZodUnion<readonly [z.ZodObject<{
|
|
98
171
|
status: z.ZodLiteral<"pending">;
|
|
99
172
|
revision: z.ZodString;
|
|
100
173
|
}, z.core.$strip>, z.ZodObject<{
|
|
101
174
|
status: z.ZodLiteral<"approved">;
|
|
102
175
|
revision: z.ZodString;
|
|
103
|
-
}, z.core.$strip>]
|
|
176
|
+
}, z.core.$strip>]>>;
|
|
104
177
|
/** Whether an Agent's App tools are still pending the owner's approval. */
|
|
105
178
|
export type AppAgentToolPolicyStatus = z.infer<typeof appAgentToolPolicyStatusSchema>;
|
|
106
179
|
/** The outcome of an owner's direct App-tool approval. */
|
|
107
|
-
export declare const appAgentToolPolicyResultSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodObject<{
|
|
180
|
+
export declare const appAgentToolPolicyResultSchema: z.ZodLazy<z.ZodUnion<readonly [z.ZodLazy<z.ZodUnion<readonly [z.ZodObject<{
|
|
108
181
|
status: z.ZodLiteral<"pending">;
|
|
109
182
|
revision: z.ZodString;
|
|
110
183
|
}, z.core.$strip>, z.ZodObject<{
|
|
111
184
|
status: z.ZodLiteral<"approved">;
|
|
112
185
|
revision: z.ZodString;
|
|
113
|
-
}, z.core.$strip>]
|
|
186
|
+
}, z.core.$strip>]>>, z.ZodObject<{
|
|
114
187
|
error: z.ZodString;
|
|
115
|
-
}, z.core.$strip>]
|
|
188
|
+
}, z.core.$strip>]>>;
|
|
116
189
|
/** The outcome of an owner's direct App-tool approval. */
|
|
117
190
|
export type AppAgentToolPolicyResult = z.infer<typeof appAgentToolPolicyResultSchema>;
|
|
118
191
|
/** Capability handle for reading and approving an Agent's App-tool policy. */
|
package/dist/agents.js
CHANGED
|
@@ -3,31 +3,40 @@ import * as z from "zod";
|
|
|
3
3
|
import { defineCapability } from "./capabilities.js";
|
|
4
4
|
import { rpcDataSchema, rpcHandleSchema, rpcMethod, rpcFetchHandleSchema, } from "./internal/rpc-contract.js";
|
|
5
5
|
import * as Schema from "effect/Schema";
|
|
6
|
+
import { avatarEnvelopeSchema, } from "@fungi.computer/sprite/avatar";
|
|
6
7
|
import { AppError } from "./errors.js";
|
|
7
8
|
import { reportCatchFailure } from "./failure.js";
|
|
8
9
|
const boundedIdentity = Schema.String.pipe(Schema.check(Schema.isMinLength(1)), Schema.check(Schema.isMaxLength(256)));
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
|
|
11
|
+
* An Agent's avatar: Sprite's Avatar v1 envelope. Apps check its shape; the
|
|
12
|
+
* host owns the character-catalog refinement when it stores one.
|
|
13
|
+
*/
|
|
14
|
+
export const appAgentAvatarSchema = Schema.declare((value) => avatarEnvelopeSchema.safeParse(value).success, { expected: "an Avatar v1 descriptor" });
|
|
15
|
+
/**
|
|
16
|
+
* Validates the wire shape of an Agent record: its id, display name, avatar,
|
|
17
|
+
* and which session operations (read, send, manage) this App may perform on
|
|
18
|
+
* it. Every Agent has an avatar: the one its owner chose, else Sprite's
|
|
19
|
+
* `seededAvatar(agentId)`. Conversations carry none of their own.
|
|
13
20
|
*/
|
|
14
21
|
export const appAgentSchema = Schema.Struct({
|
|
15
22
|
agentId: boundedIdentity,
|
|
16
23
|
name: boundedIdentity,
|
|
24
|
+
avatar: appAgentAvatarSchema,
|
|
17
25
|
sessionOperations: Schema.Array(Schema.Literals(["agent.read", "agent.send", "agent.manage"])),
|
|
18
26
|
});
|
|
19
27
|
/** The admitted AGENTS.list projection, containing only ids and display names. */
|
|
20
|
-
export const appAgentListResultSchema = z.strictObject({
|
|
28
|
+
export const appAgentListResultSchema = z.lazy(() => z.strictObject({
|
|
21
29
|
agents: z.array(z.strictObject({ agentId: z.string(), name: z.string() })),
|
|
22
|
-
});
|
|
30
|
+
}));
|
|
23
31
|
/** Computer provisioning is a Team creation choice, separate from Home policy. */
|
|
24
32
|
export const appAgentComputerSchema = Schema.Literals(["new", "none"]);
|
|
25
|
-
/** Validates Agent creation input: a name, a caller-chosen request id
|
|
26
|
-
* optional Computer provisioning choice. */
|
|
33
|
+
/** Validates Agent creation input: a name, a caller-chosen request id, an
|
|
34
|
+
* optional Computer provisioning choice and an optional chosen avatar. */
|
|
27
35
|
export const appAgentCreateInputSchema = Schema.Struct({
|
|
28
36
|
name: boundedIdentity,
|
|
29
37
|
requestId: boundedIdentity,
|
|
30
38
|
computer: Schema.optionalKey(appAgentComputerSchema),
|
|
39
|
+
avatar: Schema.optionalKey(appAgentAvatarSchema),
|
|
31
40
|
});
|
|
32
41
|
const appAgentDirectorySchema = Schema.Array(appAgentSchema);
|
|
33
42
|
const decodeAgents = Schema.decodeUnknownSync(appAgentDirectorySchema, {
|
|
@@ -36,64 +45,78 @@ const decodeAgents = Schema.decodeUnknownSync(appAgentDirectorySchema, {
|
|
|
36
45
|
const decodeAgentId = Schema.decodeUnknownSync(boundedIdentity);
|
|
37
46
|
const decodeResponse = Schema.decodeUnknownSync(Schema.instanceOf(Response));
|
|
38
47
|
/** Capability to list the Agents visible to this App in read-only form. */
|
|
39
|
-
export const agentList = defineCapability("agent.list", 1, rpcHandleSchema({
|
|
48
|
+
export const agentList = defineCapability("agent.list", 1, z.lazy(() => rpcHandleSchema({
|
|
40
49
|
list: rpcMethod(rpcDataSchema(z.unknown().transform((value) => decodeAgents(value)))),
|
|
41
|
-
}));
|
|
50
|
+
})));
|
|
42
51
|
/** Capability to create new Agents and open transports to them. */
|
|
43
|
-
export const agentManage = defineCapability("agent.manage", 1, rpcHandleSchema({
|
|
52
|
+
export const agentManage = defineCapability("agent.manage", 1, z.lazy(() => rpcHandleSchema({
|
|
44
53
|
open: rpcMethod(rpcFetchHandleSchema),
|
|
45
54
|
create: rpcMethod(rpcDataSchema(z
|
|
46
55
|
.unknown()
|
|
47
56
|
.transform((value) => Schema.decodeUnknownSync(appAgentSchema)(value)))),
|
|
48
|
-
}));
|
|
57
|
+
})));
|
|
49
58
|
/** Validates Agent rename input: the target Agent and its new display name. */
|
|
50
59
|
export const appAgentRenameInputSchema = Schema.Struct({
|
|
51
60
|
agentId: boundedIdentity,
|
|
52
61
|
name: boundedIdentity,
|
|
53
62
|
});
|
|
54
63
|
/** Owner-only capability to rename an existing Agent; not every host grants it. */
|
|
55
|
-
export const agentRename = defineCapability("agent.rename", 1, rpcHandleSchema({
|
|
64
|
+
export const agentRename = defineCapability("agent.rename", 1, z.lazy(() => rpcHandleSchema({
|
|
56
65
|
rename: rpcMethod(rpcDataSchema(z
|
|
57
66
|
.unknown()
|
|
58
67
|
.transform((value) => Schema.decodeUnknownSync(appAgentSchema)(value)))),
|
|
59
|
-
}));
|
|
68
|
+
})));
|
|
60
69
|
/** Rename an Agent through the host-granted owner-only capability. */
|
|
61
70
|
export async function renameAppAgent(capabilities, input) {
|
|
62
71
|
const request = Schema.decodeUnknownSync(appAgentRenameInputSchema)(input);
|
|
63
72
|
const agent = await capabilities.require(agentRename).rename(request);
|
|
64
73
|
return Schema.decodeUnknownSync(appAgentSchema)(agent);
|
|
65
74
|
}
|
|
75
|
+
/** Validates avatar input: the target Agent and the avatar it now wears. */
|
|
76
|
+
export const appAgentAvatarInputSchema = Schema.Struct({
|
|
77
|
+
agentId: boundedIdentity,
|
|
78
|
+
avatar: appAgentAvatarSchema,
|
|
79
|
+
});
|
|
80
|
+
/** Owner-only capability to change an existing Agent's avatar; not every host grants it. */
|
|
81
|
+
export const agentAvatar = defineCapability("agent.avatar", 1, z.lazy(() => rpcHandleSchema({
|
|
82
|
+
setAvatar: rpcMethod(rpcDataSchema(z
|
|
83
|
+
.unknown()
|
|
84
|
+
.transform((value) => Schema.decodeUnknownSync(appAgentSchema)(value)))),
|
|
85
|
+
})));
|
|
86
|
+
/** Change an Agent's avatar through the host-granted owner-only capability. */
|
|
87
|
+
export async function setAppAgentAvatar(capabilities, input) {
|
|
88
|
+
const request = Schema.decodeUnknownSync(appAgentAvatarInputSchema)(input);
|
|
89
|
+
const agent = await capabilities.require(agentAvatar).setAvatar(request);
|
|
90
|
+
return Schema.decodeUnknownSync(appAgentSchema)(agent);
|
|
91
|
+
}
|
|
66
92
|
/** One Agent's App-tool policy, as the owner-only policy capability reports it. */
|
|
67
|
-
export const appAgentToolPolicyStatusSchema = z.union([
|
|
93
|
+
export const appAgentToolPolicyStatusSchema = z.lazy(() => z.union([
|
|
68
94
|
z.object({ status: z.literal("pending"), revision: z.string() }),
|
|
69
95
|
z.object({ status: z.literal("approved"), revision: z.string() }),
|
|
70
|
-
]);
|
|
96
|
+
]));
|
|
71
97
|
/** The outcome of an owner's direct App-tool approval. */
|
|
72
|
-
export const appAgentToolPolicyResultSchema = z.union([
|
|
73
|
-
appAgentToolPolicyStatusSchema,
|
|
74
|
-
z.object({ error: z.string() }),
|
|
75
|
-
]);
|
|
98
|
+
export const appAgentToolPolicyResultSchema = z.lazy(() => z.union([appAgentToolPolicyStatusSchema, z.object({ error: z.string() })]));
|
|
76
99
|
/** Owner-only capability to read and approve an Agent's App-tool policy. */
|
|
77
|
-
export const agentToolPolicy = defineCapability("agent.toolPolicy", 1, rpcHandleSchema({
|
|
100
|
+
export const agentToolPolicy = defineCapability("agent.toolPolicy", 1, z.lazy(() => rpcHandleSchema({
|
|
78
101
|
status: rpcMethod(rpcDataSchema(z.union([appAgentToolPolicyStatusSchema, z.null()]))),
|
|
79
102
|
approve: rpcMethod(rpcDataSchema(appAgentToolPolicyResultSchema)),
|
|
80
|
-
}));
|
|
103
|
+
})));
|
|
81
104
|
/**
|
|
82
105
|
* Capability for read-only Agent sessions: open a transport to an
|
|
83
106
|
* existing Agent, or read the member's inbox feed.
|
|
84
107
|
*/
|
|
85
|
-
export const agentSessionRead = defineCapability("agent.read", 1, rpcHandleSchema({
|
|
108
|
+
export const agentSessionRead = defineCapability("agent.read", 1, z.lazy(() => rpcHandleSchema({
|
|
86
109
|
open: rpcMethod(rpcFetchHandleSchema),
|
|
87
110
|
openInbox: rpcMethod(rpcFetchHandleSchema),
|
|
88
|
-
}));
|
|
111
|
+
})));
|
|
89
112
|
/**
|
|
90
113
|
* Capability for read-write Agent sessions: open a transport to an
|
|
91
114
|
* existing Agent and send to it, including the member's inbox feed.
|
|
92
115
|
*/
|
|
93
|
-
export const agentSessionWrite = defineCapability("agent.send", 1, rpcHandleSchema({
|
|
116
|
+
export const agentSessionWrite = defineCapability("agent.send", 1, z.lazy(() => rpcHandleSchema({
|
|
94
117
|
open: rpcMethod(rpcFetchHandleSchema),
|
|
95
118
|
openInbox: rpcMethod(rpcFetchHandleSchema),
|
|
96
|
-
}));
|
|
119
|
+
})));
|
|
97
120
|
/** List the Agents in the host-granted Team or local-project scope. */
|
|
98
121
|
export async function listAppAgents(capabilities) {
|
|
99
122
|
return decodeAgents(await capabilities.require(agentList).list());
|
package/dist/apps.js
CHANGED
|
@@ -36,12 +36,12 @@ export const appRoleChoiceSchema = z
|
|
|
36
36
|
* `role` answers which App that open would reach (null when none fills it),
|
|
37
37
|
* so a caller can name or hide its entry without hard-coding another App.
|
|
38
38
|
*/
|
|
39
|
-
export const appsOpen = defineCapability("apps.open", 1, rpcHandleSchema({
|
|
39
|
+
export const appsOpen = defineCapability("apps.open", 1, z.lazy(() => rpcHandleSchema({
|
|
40
40
|
open: rpcVoid,
|
|
41
41
|
role: rpcMethod(rpcDataSchema(appRoleChoiceSchema)),
|
|
42
|
-
}));
|
|
42
|
+
})));
|
|
43
43
|
export const openApp = (directory, input) => directory.require(appsOpen).open(input);
|
|
44
44
|
/** Call a declared method of another App as the signed-in member. Caller grants never travel. */
|
|
45
|
-
export const appsCall = defineCapability("apps.call", 1, rpcHandleSchema({
|
|
45
|
+
export const appsCall = defineCapability("apps.call", 1, z.lazy(() => rpcHandleSchema({
|
|
46
46
|
call: rpcMethod(rpcDataSchema(z.unknown().transform((value) => parseJsonValue(value)))),
|
|
47
|
-
}));
|
|
47
|
+
})));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
|
-
import type { GillCall, GillReply } from "@fungi.computer/gills";
|
|
2
|
+
import type { GillCall, GillReply, ResultRow } from "@fungi.computer/gills";
|
|
3
3
|
import type { AppBackendGill } from "./gills.js";
|
|
4
4
|
export type { AppBackendGill } from "./gills.js";
|
|
5
5
|
import { type AppMethodCallContext } from "@fungi.computer/puffball/app-method-runtime";
|
|
@@ -10,10 +10,10 @@ export { pending, pendingSchema, type Pending } from "./pending.js";
|
|
|
10
10
|
/** EVENTS.emit acknowledges delivery with native void, not a JSON value. */
|
|
11
11
|
export declare const appEventEmitResultSchema: z.ZodUndefined;
|
|
12
12
|
/** App-originated Session send refusal; retry advice is a duration, not a timestamp. */
|
|
13
|
-
export declare const appSendBudgetRefusalSchema: z.ZodObject<{
|
|
13
|
+
export declare const appSendBudgetRefusalSchema: z.ZodLazy<z.ZodObject<{
|
|
14
14
|
error: z.ZodLiteral<"send_budget_exceeded">;
|
|
15
15
|
retryAfterMs: z.ZodNumber;
|
|
16
|
-
}, z.core.$strict
|
|
16
|
+
}, z.core.$strict>>;
|
|
17
17
|
/** A declined Session send, with how long to wait before retrying. */
|
|
18
18
|
export type AppSendBudgetRefusal = z.output<typeof appSendBudgetRefusalSchema>;
|
|
19
19
|
/** A method's schemas own both its TypeScript contract and JSON boundary. */
|
|
@@ -27,19 +27,56 @@ export type MethodPolicy = Readonly<{
|
|
|
27
27
|
anonymous?: true;
|
|
28
28
|
/** Allow the shared Pending result while this method is still working. */
|
|
29
29
|
pending?: true;
|
|
30
|
+
/** Past tense for timelines ("made", "wrote"); the row itself comes from {@link MethodPresentation}. */
|
|
31
|
+
present?: Readonly<{
|
|
32
|
+
verb: string;
|
|
33
|
+
}>;
|
|
34
|
+
}>;
|
|
35
|
+
/** Decodes and bounds result rows; see `resultRows` in `@fungi.computer/agar/method-presentation`. */
|
|
36
|
+
export type ResultRowCodec = Readonly<{
|
|
37
|
+
/** Check one projected row against the shared row's bounds; throws when it breaks them. */
|
|
38
|
+
decode: (row: ResultRow) => ResultRow;
|
|
39
|
+
/** The row's JSON boundary, as the generated `present` method's output. */
|
|
40
|
+
schema: z.ZodType;
|
|
41
|
+
}>;
|
|
42
|
+
/**
|
|
43
|
+
* How a finished call reads to a person: a pure projection run in the App
|
|
44
|
+
* backend. `rows` is `resultRows` from
|
|
45
|
+
* `@fungi.computer/agar/method-presentation`; only a backend that presents
|
|
46
|
+
* imports it, so one without presentations carries no row decoder.
|
|
47
|
+
*/
|
|
48
|
+
export type MethodPresentation<I, O> = Readonly<{
|
|
49
|
+
/** Past tense for timelines: "made", "wrote", "pushed". */
|
|
50
|
+
verb: string;
|
|
51
|
+
/** Pure: one finished call to the row a person reads. */
|
|
52
|
+
row: (call: Readonly<{
|
|
53
|
+
input: I;
|
|
54
|
+
output: O;
|
|
55
|
+
}>) => ResultRow;
|
|
56
|
+
/** The shared row codec, `resultRows`. */
|
|
57
|
+
rows: ResultRowCodec;
|
|
30
58
|
}>;
|
|
59
|
+
/** Name of the generated, hidden read method that projects a finished call into its row. */
|
|
60
|
+
export declare const presentMethodName = "present";
|
|
31
61
|
/** Prepared method export consumed by the backend and its build. */
|
|
32
62
|
export type AppBackendMethod<Context = void> = Readonly<{
|
|
33
63
|
policy: MethodPolicy;
|
|
34
64
|
input: z.ZodType;
|
|
35
65
|
output: z.ZodType;
|
|
66
|
+
/** Parse a recorded call against this method's schemas and project its row. */
|
|
67
|
+
present?: (input: WhistleJsonValue, output: WhistleJsonValue) => ResultRow;
|
|
68
|
+
/** The row's JSON boundary, present exactly when `present` is. */
|
|
69
|
+
presentRow?: z.ZodType;
|
|
36
70
|
/** Parse the raw input, run the handler, and return its JSON result. */
|
|
37
71
|
call: (input: WhistleJsonValue, context: Context, caller: AppMethodCallContext) => Promise<WhistleJsonValue>;
|
|
38
72
|
}>;
|
|
73
|
+
/** The prepared methods of one backend, keyed by their public names. */
|
|
74
|
+
export type AppBackendMethods<Context = void> = Readonly<Record<string, AppBackendMethod<Context>>>;
|
|
39
75
|
/** Define a typed method once; neither discovery nor builds execute its handler. */
|
|
40
|
-
export declare function defineAppMethod<I extends z.ZodType, O extends z.ZodType, Context = void>(method: MethodPolicy & {
|
|
76
|
+
export declare function defineAppMethod<I extends z.ZodType, O extends z.ZodType, Context = void>(method: Omit<MethodPolicy, "present"> & {
|
|
41
77
|
input: I;
|
|
42
78
|
output: O;
|
|
79
|
+
present?: MethodPresentation<z.output<I>, z.output<O>>;
|
|
43
80
|
} & ({
|
|
44
81
|
pending: true;
|
|
45
82
|
handler: (input: z.output<I>, context: Context, caller: AppMethodCallContext) => z.input<O> | Pending | Promise<z.input<O> | Pending>;
|
|
@@ -6,10 +6,12 @@ export { pending, pendingSchema } from "./pending.js";
|
|
|
6
6
|
/** EVENTS.emit acknowledges delivery with native void, not a JSON value. */
|
|
7
7
|
export const appEventEmitResultSchema = z.undefined();
|
|
8
8
|
/** App-originated Session send refusal; retry advice is a duration, not a timestamp. */
|
|
9
|
-
export const appSendBudgetRefusalSchema = z.strictObject({
|
|
9
|
+
export const appSendBudgetRefusalSchema = z.lazy(() => z.strictObject({
|
|
10
10
|
error: z.literal("send_budget_exceeded"),
|
|
11
11
|
retryAfterMs: z.number().int().min(1).max(60_000),
|
|
12
|
-
});
|
|
12
|
+
}));
|
|
13
|
+
/** Name of the generated, hidden read method that projects a finished call into its row. */
|
|
14
|
+
export const presentMethodName = "present";
|
|
13
15
|
/** Define a typed method once; neither discovery nor builds execute its handler. */
|
|
14
16
|
export function defineAppMethod(method) {
|
|
15
17
|
const output = method.pending === true
|
|
@@ -26,16 +28,31 @@ export function defineAppMethod(method) {
|
|
|
26
28
|
policy = { ...policy, hidden: true };
|
|
27
29
|
if (method.anonymous === true)
|
|
28
30
|
policy = { ...policy, anonymous: true };
|
|
31
|
+
const call = async (rawInput, context, rawCaller) => {
|
|
32
|
+
const caller = parseAppMethodCallContext(rawCaller);
|
|
33
|
+
const parsed = method.input.parse(rawInput);
|
|
34
|
+
const result = await method.handler(parsed, context, caller);
|
|
35
|
+
return z.json().parse(output.parse(result));
|
|
36
|
+
};
|
|
37
|
+
const presentation = method.present;
|
|
38
|
+
if (presentation === undefined)
|
|
39
|
+
return Object.freeze({
|
|
40
|
+
policy: Object.freeze(policy),
|
|
41
|
+
input: method.input,
|
|
42
|
+
output,
|
|
43
|
+
call,
|
|
44
|
+
});
|
|
45
|
+
policy = { ...policy, present: Object.freeze({ verb: presentation.verb }) };
|
|
29
46
|
return Object.freeze({
|
|
30
47
|
policy: Object.freeze(policy),
|
|
31
48
|
input: method.input,
|
|
32
49
|
output,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
50
|
+
present: (rawInput, rawOutput) => presentation.rows.decode(presentation.row({
|
|
51
|
+
input: method.input.parse(rawInput),
|
|
52
|
+
output: method.output.parse(rawOutput),
|
|
53
|
+
})),
|
|
54
|
+
presentRow: presentation.rows.schema,
|
|
55
|
+
call,
|
|
39
56
|
});
|
|
40
57
|
}
|
|
41
58
|
/** The generated method RPC answers with a typed reply: a handler's
|
|
@@ -54,9 +71,52 @@ async function methodReply(run) {
|
|
|
54
71
|
});
|
|
55
72
|
}
|
|
56
73
|
}
|
|
74
|
+
const presentInput = z.strictObject({
|
|
75
|
+
method: z.string().min(1).max(80),
|
|
76
|
+
input: z.json(),
|
|
77
|
+
output: z.json(),
|
|
78
|
+
});
|
|
79
|
+
const generatedPresentMethods = new WeakSet();
|
|
80
|
+
/**
|
|
81
|
+
* Methods that declare a presentation share one generated, hidden read method
|
|
82
|
+
* that projects a recorded call into its row, so hosts reach it through the
|
|
83
|
+
* ordinary method admission instead of a second invocation path.
|
|
84
|
+
*/
|
|
85
|
+
function withPresentation(all) {
|
|
86
|
+
// A backend rebuilt from another definition's methods regenerates its own.
|
|
87
|
+
const methods = Object.fromEntries(Object.entries(all).filter(([name, method]) => name !== presentMethodName || !generatedPresentMethods.has(method)));
|
|
88
|
+
const presenting = new Map(Object.entries(methods).filter(([, method]) => method.present !== undefined));
|
|
89
|
+
const presentRow = [...presenting.values()][0]?.presentRow;
|
|
90
|
+
if (presentRow === undefined)
|
|
91
|
+
return methods;
|
|
92
|
+
if (Object.hasOwn(methods, presentMethodName))
|
|
93
|
+
throw new Error(`App backend method is reserved: ${presentMethodName}`);
|
|
94
|
+
const present = Object.freeze({
|
|
95
|
+
policy: Object.freeze({
|
|
96
|
+
description: "Project one finished call of a presenting method into its result row.",
|
|
97
|
+
effect: "read",
|
|
98
|
+
requires: Object.freeze([]),
|
|
99
|
+
hidden: true,
|
|
100
|
+
}),
|
|
101
|
+
input: presentInput,
|
|
102
|
+
output: presentRow,
|
|
103
|
+
call: (rawInput) => Promise.resolve().then(() => {
|
|
104
|
+
const request = presentInput.parse(rawInput);
|
|
105
|
+
const row = presenting
|
|
106
|
+
.get(request.method)
|
|
107
|
+
?.present?.(request.input, request.output);
|
|
108
|
+
if (row === undefined)
|
|
109
|
+
throw new Error(`Undeclared App presentation: ${request.method}`);
|
|
110
|
+
return z.json().parse(presentRow.parse(row));
|
|
111
|
+
}),
|
|
112
|
+
});
|
|
113
|
+
generatedPresentMethods.add(present);
|
|
114
|
+
return { ...methods, [presentMethodName]: present };
|
|
115
|
+
}
|
|
57
116
|
/** Generate the API from the method exports; callers cannot supply a second catalog. */
|
|
58
117
|
export function defineAppBackend(options) {
|
|
59
|
-
const
|
|
118
|
+
const declared = withPresentation(options.methods);
|
|
119
|
+
const methods = new Map(Object.entries(declared));
|
|
60
120
|
for (const name of methods.keys())
|
|
61
121
|
if (!isAppApiMethodName(name))
|
|
62
122
|
throw new Error(`Invalid App backend method name: ${name}`);
|
|
@@ -97,7 +157,7 @@ export function defineAppBackend(options) {
|
|
|
97
157
|
});
|
|
98
158
|
};
|
|
99
159
|
let definition = {
|
|
100
|
-
methods: Object.freeze({ ...
|
|
160
|
+
methods: Object.freeze({ ...declared }),
|
|
101
161
|
implement: (implementation) => {
|
|
102
162
|
const members = new Map();
|
|
103
163
|
let prototype = implementation.prototype;
|
package/dist/backend.js
CHANGED
|
@@ -3,18 +3,18 @@ import { defineCapability } from "./capabilities.js";
|
|
|
3
3
|
import { parseJsonValue } from "@fungi.computer/whistle/wire";
|
|
4
4
|
import { rpcDataSchema, rpcHandleSchema, rpcMethod, } from "./internal/rpc-contract.js";
|
|
5
5
|
/** Invoke this App's admitted backend. The App defines its JSON request/result. */
|
|
6
|
-
export const appBackend = defineCapability("app.backend", 1, rpcHandleSchema({
|
|
6
|
+
export const appBackend = defineCapability("app.backend", 1, z.lazy(() => rpcHandleSchema({
|
|
7
7
|
request: rpcMethod(rpcDataSchema(z.unknown().transform((value) => parseJsonValue(value)))),
|
|
8
|
-
}));
|
|
8
|
+
})));
|
|
9
9
|
/**
|
|
10
10
|
* Call one of this App's declared, typed methods through its host. Unlike
|
|
11
11
|
* `appBackend`, the host knows which method is called, so it can apply the
|
|
12
12
|
* method's declared effect (for example, allow only `read` methods to a
|
|
13
13
|
* visitor of a public App).
|
|
14
14
|
*/
|
|
15
|
-
export const appMethods = defineCapability("app.methods", 1, rpcHandleSchema({
|
|
15
|
+
export const appMethods = defineCapability("app.methods", 1, z.lazy(() => rpcHandleSchema({
|
|
16
16
|
call: rpcMethod(rpcDataSchema(z.unknown().transform((value) => parseJsonValue(value)))),
|
|
17
|
-
}));
|
|
17
|
+
})));
|
|
18
18
|
/** The admitting host overwrites this header from its authenticated principal.
|
|
19
19
|
* App request bodies and incoming browser headers never supply this identity. */
|
|
20
20
|
export const appBackendActorHeader = "X-Agar-Actor-Id";
|
package/dist/channels.js
CHANGED
|
@@ -84,14 +84,14 @@ export const appWebsiteReplyResponseSchema = z.strictObject({
|
|
|
84
84
|
status: z.literal("sent"),
|
|
85
85
|
});
|
|
86
86
|
/** Reading website conversations is never an automatic default-App grant. */
|
|
87
|
-
export const channelsRead = defineCapability("channels.read", 1, rpcHandleSchema({
|
|
87
|
+
export const channelsRead = defineCapability("channels.read", 1, z.lazy(() => rpcHandleSchema({
|
|
88
88
|
list: rpcMethod(rpcDataSchema(appWebsitePageSchema)),
|
|
89
89
|
conversations: rpcMethod(rpcDataSchema(appWebsiteConversationPageSchema)),
|
|
90
|
-
}));
|
|
90
|
+
})));
|
|
91
91
|
/** Member-only takeover; separate consent from read-only channel access. */
|
|
92
|
-
export const channelsPersonalManage = defineCapability("channels.personal.manage", 1, rpcHandleSchema({
|
|
92
|
+
export const channelsPersonalManage = defineCapability("channels.personal.manage", 1, z.lazy(() => rpcHandleSchema({
|
|
93
93
|
hold: rpcMethod(rpcDataSchema(appWebsiteConversationSchema)),
|
|
94
94
|
release: rpcMethod(rpcDataSchema(appWebsiteConversationSchema)),
|
|
95
95
|
dismiss: rpcMethod(rpcDataSchema(appWebsiteConversationSchema)),
|
|
96
96
|
reply: rpcMethod(rpcDataSchema(appWebsiteReplyResponseSchema)),
|
|
97
|
-
}));
|
|
97
|
+
})));
|