@collegium/sdk 0.0.1-beta.6 → 0.0.1-beta.8
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 +12 -0
- package/dist/index.d.ts +1 -150
- package/dist/testing.d.ts +16 -0
- package/dist/testing.js +71 -0
- package/dist/tool-CN2DS668.d.ts +193 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -50,6 +50,18 @@ export default defineTool({
|
|
|
50
50
|
|
|
51
51
|
A tool with `approval` always stops for a human, who sees the full payload before it runs; one without never gates. The channel and the trace disclose both, line by line. `execute` returns the text the model reads, and raises the two failures a tool controls through `err`: `invalidArguments` continues the turn, `unresolved` ends it as an unconfirmed side effect.
|
|
52
52
|
|
|
53
|
+
**Testing.** `@collegium/sdk/testing` builds the context `execute` receives, over in-memory storage that validates and parses as the deployment's store does. Pass your config; settings go through your schema, so defaults apply.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { createTestContext, PluginToolFailureError } from '@collegium/sdk/testing';
|
|
57
|
+
|
|
58
|
+
const context = createTestContext(config, { settings: { maxContacts: 1 } });
|
|
59
|
+
await save.execute({ email: 'ana@example.com', id: 'ana', name: 'Ana' }, context);
|
|
60
|
+
await expect(save.execute({ email: 'ben@example.com', id: 'ben', name: 'Ben' }, context)).rejects.toThrow(
|
|
61
|
+
PluginToolFailureError
|
|
62
|
+
);
|
|
63
|
+
```
|
|
64
|
+
|
|
53
65
|
**zod is a peer dependency.** Install it beside the SDK and import it directly. A plugin may import `@collegium/sdk`, `zod`, and `node:` builtins; the compiler refuses every other bare specifier at boot.
|
|
54
66
|
|
|
55
67
|
**Your installed copies are for development.** The deployment compiles a mounted plugin against the SDK and zod its image carries, not the copies in your `node_modules` — those serve your editor, `tsc`, and your tests. Exactly one zod runs in the process.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,151 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Promisable } from "type-fest";
|
|
3
|
-
//#region src/config.d.ts
|
|
4
|
-
type CollectionsDeclaration$1 = {
|
|
5
|
-
readonly [key: string]: z.ZodType;
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* The config file's default export: the settings schema agents are configured by, and the storage
|
|
9
|
-
* collections the plugin owns. Its generics are what carry the settings and storage types to every
|
|
10
|
-
* tool, through `Register`.
|
|
11
|
-
*/
|
|
12
|
-
type PluginConfig<TSettings extends undefined | z.ZodType = undefined | z.ZodType, TCollections extends CollectionsDeclaration$1 = CollectionsDeclaration$1> = {
|
|
13
|
-
readonly settings: TSettings;
|
|
14
|
-
readonly storage: TCollections;
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* The augmentation point. `src/config.ts` declares its config here, and every tool file receives
|
|
18
|
-
* the declared settings and storage types without importing the config:
|
|
19
|
-
*
|
|
20
|
-
* ```ts
|
|
21
|
-
* declare module '@collegium/sdk' {
|
|
22
|
-
* interface Register { config: typeof config }
|
|
23
|
-
* }
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
|
-
interface Register {}
|
|
27
|
-
type RegisteredConfig = Register extends {
|
|
28
|
-
readonly config: infer TConfig extends PluginConfig;
|
|
29
|
-
} ? TConfig : PluginConfig;
|
|
30
|
-
declare function defineConfig<TSettings extends undefined | z.ZodType = undefined, const TCollections extends CollectionsDeclaration$1 = {}>(config: {
|
|
31
|
-
readonly settings?: TSettings;
|
|
32
|
-
readonly storage?: TCollections;
|
|
33
|
-
}): PluginConfig<TSettings, TCollections>;
|
|
34
|
-
//#endregion
|
|
35
|
-
//#region ../core/src/approvals/approvals.types.d.ts
|
|
36
|
-
/** how a gated tool's approval payload is presented (§6.2): collapsed behind a control, or verbatim */
|
|
37
|
-
type ApprovalPayloadPresentation = 'collapse' | 'verbatim';
|
|
38
|
-
//#endregion
|
|
39
|
-
//#region ../core/src/utils/token.utils.d.ts
|
|
40
|
-
declare const SERVICE_INSTANCE: unique symbol;
|
|
41
|
-
/**
|
|
42
|
-
* A NestJS-compatible injection token branded with the instance type it resolves to. Declared in a
|
|
43
|
-
* leaf `<module>.tokens.ts` beside `import type` of the service alone, which is what keeps a
|
|
44
|
-
* toolset declaration inert (§2): the entrypoint and provisioning import one without pulling the
|
|
45
|
-
* service's runtime module into their graphs.
|
|
46
|
-
*/
|
|
47
|
-
type ServiceToken<TInstance> = {
|
|
48
|
-
readonly [SERVICE_INSTANCE]?: TInstance;
|
|
49
|
-
} & symbol;
|
|
50
|
-
//#endregion
|
|
51
|
-
//#region ../core/src/tools/tools.types.d.ts
|
|
52
|
-
/** the four facts of the running turn (§4) — everything else a tool needs, its toolset declares */
|
|
53
|
-
type ToolTurnScope = {
|
|
54
|
-
readonly agentUsername: string;
|
|
55
|
-
readonly channelId: string;
|
|
56
|
-
/** provenance for anything a tool records; null on a turn no post triggered */
|
|
57
|
-
readonly triggeringPostId: null | string;
|
|
58
|
-
readonly turnId: string;
|
|
59
|
-
};
|
|
60
|
-
/** §6.2 — the full payload the approver reads; presence of the `approval` hook is what gates a tool (§5) */
|
|
61
|
-
type ToolApprovalPayload = {
|
|
62
|
-
body: string;
|
|
63
|
-
presentation: ApprovalPayloadPresentation;
|
|
64
|
-
};
|
|
65
|
-
/**
|
|
66
|
-
* A durable record's disclosure (§3.6), returned by the tool that created it; the turn writes the
|
|
67
|
-
* event and the trace lines. `reference` names the record for later reads, e.g. a memory id.
|
|
68
|
-
*/
|
|
69
|
-
type ToolDisclosure = {
|
|
70
|
-
readonly body: string;
|
|
71
|
-
readonly description: string;
|
|
72
|
-
readonly reference: string;
|
|
73
|
-
readonly supersededDescriptions?: readonly string[];
|
|
74
|
-
};
|
|
75
|
-
//#endregion
|
|
76
|
-
//#region ../core/src/plugins/plugins.types.d.ts
|
|
77
|
-
/** what a plugin tool body may return: the text alone, or the text beside a durable record's disclosure (§3.4) */
|
|
78
|
-
type PluginToolOutput = string | {
|
|
79
|
-
readonly disclosure?: ToolDisclosure;
|
|
80
|
-
readonly text: string;
|
|
81
|
-
};
|
|
82
|
-
/**
|
|
83
|
-
* The two failures a tool body may raise itself — the rest of the taxonomy (§7.1) is the
|
|
84
|
-
* framework's to raise. Each throws; the perimeter wrapper maps the throw into the taxonomy.
|
|
85
|
-
*/
|
|
86
|
-
type PluginToolErr = {
|
|
87
|
-
/** the arguments were rejected — returned to the model as the tool result; the turn continues */
|
|
88
|
-
invalidArguments(message: string): never;
|
|
89
|
-
/** a committed side effect whose outcome cannot be established; the turn ends stating the ambiguity */
|
|
90
|
-
unresolved(message: string): never;
|
|
91
|
-
};
|
|
92
|
-
/** one tool as a plugin declares it: the framework's tool minus `budgetExempt`, returning plain output */
|
|
93
|
-
type PluginToolDeclaration<TContext, TParams extends z.ZodType> = {
|
|
94
|
-
/** present ⇒ the tool always gates (§5); renders the payload the approver reads and cannot decline */
|
|
95
|
-
approval?(args: z.infer<TParams>): ToolApprovalPayload;
|
|
96
|
-
readonly description: string;
|
|
97
|
-
execute(args: z.infer<TParams>, context: TContext): Promisable<PluginToolOutput>;
|
|
98
|
-
readonly parameters: TParams;
|
|
99
|
-
/** §7.2 — whether a timed-out call may be reported to the model as a plain failure; false ends the turn as unconfirmable */
|
|
100
|
-
readonly retryable?: boolean;
|
|
101
|
-
readonly timeoutMs?: number;
|
|
102
|
-
/** §8.1 — the one-line summary beside the name in the status post; absent shows the name alone */
|
|
103
|
-
traceDetail?(args: z.infer<TParams>): string;
|
|
104
|
-
};
|
|
105
|
-
//#endregion
|
|
106
|
-
//#region ../core/src/toolsets/toolsets.types.d.ts
|
|
107
|
-
/** `settings`, `storage`, and `turn` are the context's own keys, so a service may not claim them */
|
|
108
|
-
type ServicesDeclaration = {
|
|
109
|
-
readonly [key: string]: ServiceToken<unknown>;
|
|
110
|
-
} & {
|
|
111
|
-
readonly settings?: never;
|
|
112
|
-
readonly storage?: never;
|
|
113
|
-
readonly turn?: never;
|
|
114
|
-
};
|
|
115
|
-
type CollectionsDeclaration = {
|
|
116
|
-
readonly [key: string]: z.ZodType;
|
|
117
|
-
};
|
|
118
|
-
type EmptyDeclaration = {};
|
|
119
|
-
/** a toolset-scoped handle over one declared storage collection; rows are validated on write and parsed on read */
|
|
120
|
-
type ToolsetCollection<TValue> = {
|
|
121
|
-
delete(key: string): Promise<boolean>;
|
|
122
|
-
get(key: string): Promise<null | TValue>;
|
|
123
|
-
list(): Promise<{
|
|
124
|
-
key: string;
|
|
125
|
-
value: TValue;
|
|
126
|
-
}[]>;
|
|
127
|
-
put(key: string, value: TValue): Promise<void>;
|
|
128
|
-
};
|
|
129
|
-
/**
|
|
130
|
-
* What `execute` receives, assembled from exactly what the toolset declared (§4): each service
|
|
131
|
-
* under its own name, `settings` and `storage` only when declared, and always the turn. Reaching
|
|
132
|
-
* anything undeclared is a compile error.
|
|
133
|
-
*/
|
|
134
|
-
type ToolsetContext<TServices extends ServicesDeclaration = EmptyDeclaration, TSettings extends undefined | z.ZodType = undefined, TCollections extends CollectionsDeclaration = EmptyDeclaration> = { readonly [K in keyof TServices]: TServices[K] extends ServiceToken<infer TInstance> ? TInstance : never; } & {
|
|
135
|
-
readonly turn: ToolTurnScope;
|
|
136
|
-
} & (keyof TCollections extends never ? unknown : {
|
|
137
|
-
readonly storage: { readonly [K in keyof TCollections]: ToolsetCollection<z.infer<TCollections[K]>>; };
|
|
138
|
-
}) & (TSettings extends z.ZodType ? {
|
|
139
|
-
readonly settings: z.infer<TSettings>;
|
|
140
|
-
} : unknown);
|
|
141
|
-
//#endregion
|
|
142
|
-
//#region src/tool.d.ts
|
|
143
|
-
/** what `execute` receives: the registered config's settings and storage, the failure raisers, and the four facts of the turn */
|
|
144
|
-
type ToolContext = ToolsetContext<EmptyDeclaration, RegisteredConfig['settings'], RegisteredConfig['storage']> & {
|
|
145
|
-
readonly err: PluginToolErr;
|
|
146
|
-
};
|
|
147
|
-
type PluginTool<TParams extends z.ZodType> = PluginToolDeclaration<ToolContext, TParams>;
|
|
148
|
-
/** identity at runtime; what it is for is typing `args` from `parameters` across the whole declaration */
|
|
149
|
-
declare function defineTool<TParams extends z.ZodType>(tool: PluginTool<TParams>): PluginTool<TParams>;
|
|
150
|
-
//#endregion
|
|
1
|
+
import { c as ToolTurnScope, d as defineConfig, i as defineTool, n as ToolContext, o as ToolApprovalPayload, s as ToolDisclosure, t as PluginTool, u as Register } from "./tool-CN2DS668.js";
|
|
151
2
|
export { type PluginTool, type Register, type ToolApprovalPayload, type ToolContext, type ToolDisclosure, type ToolTurnScope, defineConfig, defineTool };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { a as PluginToolFailureError, c as ToolTurnScope, l as PluginConfig, r as ToolContextFor } from "./tool-CN2DS668.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/testing.d.ts
|
|
4
|
+
/** `settings` as the declared schema accepts them, so defaults apply as they do at boot; `turn` overrides the four facts */
|
|
5
|
+
type TestContextOptions<TConfig extends PluginConfig> = {
|
|
6
|
+
readonly settings?: TConfig['settings'] extends z.ZodType ? z.input<TConfig['settings']> : never;
|
|
7
|
+
readonly turn?: Partial<ToolTurnScope>;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* The context a deployment hands `execute`, over in-memory storage: each declared collection
|
|
11
|
+
* validates on write and parses on read as the real store does, settings pass through the declared
|
|
12
|
+
* schema so defaults apply, and `err` raises exactly what the framework's wrapper catches.
|
|
13
|
+
*/
|
|
14
|
+
declare function createTestContext<TConfig extends PluginConfig>(config: TConfig, options?: TestContextOptions<TConfig>): ToolContextFor<TConfig>;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { PluginToolFailureError, TestContextOptions, createTestContext };
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
//#region ../core/dist/plugins/plugins.errors.js
|
|
2
|
+
/** what `err.invalidArguments` and `err.unresolved` throw; the perimeter wrapper catches it and nothing else */
|
|
3
|
+
var PluginToolFailureError = class extends Error {
|
|
4
|
+
failure;
|
|
5
|
+
constructor(failure) {
|
|
6
|
+
super(failure.message);
|
|
7
|
+
this.failure = failure;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region ../core/dist/plugins/plugins.utils.js
|
|
12
|
+
/** what a plugin tool receives as `err`; shared with the SDK's testing entry, so a test raises the failure a deployment would */
|
|
13
|
+
const PLUGIN_TOOL_ERR = {
|
|
14
|
+
invalidArguments(message) {
|
|
15
|
+
throw new PluginToolFailureError({
|
|
16
|
+
kind: "invalid-arguments",
|
|
17
|
+
message
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
unresolved(message) {
|
|
21
|
+
throw new PluginToolFailureError({
|
|
22
|
+
kind: "unresolved",
|
|
23
|
+
message
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/testing.ts
|
|
29
|
+
const DEFAULT_TURN = {
|
|
30
|
+
agentUsername: "tester",
|
|
31
|
+
channelId: "test-channel",
|
|
32
|
+
triggeringPostId: null,
|
|
33
|
+
turnId: "test-turn"
|
|
34
|
+
};
|
|
35
|
+
function createCollection(schema) {
|
|
36
|
+
const rows = /* @__PURE__ */ new Map();
|
|
37
|
+
return {
|
|
38
|
+
delete: (key) => Promise.try(() => rows.delete(key)),
|
|
39
|
+
get: (key) => Promise.try(() => rows.has(key) ? schema.parse(rows.get(key)) : null),
|
|
40
|
+
list: () => Promise.try(() => [...rows].map(([key, value]) => ({
|
|
41
|
+
key,
|
|
42
|
+
value: schema.parse(value)
|
|
43
|
+
}))),
|
|
44
|
+
put: (key, value) => Promise.try(() => {
|
|
45
|
+
rows.set(key, schema.parse(value));
|
|
46
|
+
})
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The context a deployment hands `execute`, over in-memory storage: each declared collection
|
|
51
|
+
* validates on write and parses on read as the real store does, settings pass through the declared
|
|
52
|
+
* schema so defaults apply, and `err` raises exactly what the framework's wrapper catches.
|
|
53
|
+
*/
|
|
54
|
+
function createTestContext(config, options = {}) {
|
|
55
|
+
const storage = Object.fromEntries(Object.entries(config.storage).map(([name, schema]) => [name, createCollection(schema)]));
|
|
56
|
+
const context = {
|
|
57
|
+
err: PLUGIN_TOOL_ERR,
|
|
58
|
+
storage,
|
|
59
|
+
turn: {
|
|
60
|
+
...DEFAULT_TURN,
|
|
61
|
+
...options.turn
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const settings = config.settings === void 0 ? {} : { settings: config.settings.parse(options.settings ?? {}) };
|
|
65
|
+
return {
|
|
66
|
+
...context,
|
|
67
|
+
...settings
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
export { PluginToolFailureError, createTestContext };
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Promisable } from "type-fest";
|
|
3
|
+
//#region src/config.d.ts
|
|
4
|
+
type CollectionsDeclaration$1 = {
|
|
5
|
+
readonly [key: string]: z.ZodType;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* The config file's default export: the settings schema agents are configured by, and the storage
|
|
9
|
+
* collections the plugin owns. Its generics are what carry the settings and storage types to every
|
|
10
|
+
* tool, through `Register`.
|
|
11
|
+
*/
|
|
12
|
+
type PluginConfig<TSettings extends undefined | z.ZodType = undefined | z.ZodType, TCollections extends CollectionsDeclaration$1 = CollectionsDeclaration$1> = {
|
|
13
|
+
readonly settings: TSettings;
|
|
14
|
+
readonly storage: TCollections;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The augmentation point. `src/config.ts` declares its config here, and every tool file receives
|
|
18
|
+
* the declared settings and storage types without importing the config:
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* declare module '@collegium/sdk' {
|
|
22
|
+
* interface Register { config: typeof config }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
interface Register {}
|
|
27
|
+
type RegisteredConfig = Register extends {
|
|
28
|
+
readonly config: infer TConfig extends PluginConfig;
|
|
29
|
+
} ? TConfig : PluginConfig;
|
|
30
|
+
declare function defineConfig<TSettings extends undefined | z.ZodType = undefined, const TCollections extends CollectionsDeclaration$1 = {}>(config: {
|
|
31
|
+
readonly settings?: TSettings;
|
|
32
|
+
readonly storage?: TCollections;
|
|
33
|
+
}): PluginConfig<TSettings, TCollections>;
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region ../core/src/approvals/approvals.types.d.ts
|
|
36
|
+
/** how a gated tool's approval payload is presented (§6.2): collapsed behind a control, or verbatim */
|
|
37
|
+
type ApprovalPayloadPresentation = 'collapse' | 'verbatim';
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region ../core/src/utils/token.utils.d.ts
|
|
40
|
+
declare const SERVICE_INSTANCE: unique symbol;
|
|
41
|
+
/**
|
|
42
|
+
* A NestJS-compatible injection token branded with the instance type it resolves to. Declared in a
|
|
43
|
+
* leaf `<module>.tokens.ts` beside `import type` of the service alone, which is what keeps a
|
|
44
|
+
* toolset declaration inert (§2): the entrypoint and provisioning import one without pulling the
|
|
45
|
+
* service's runtime module into their graphs.
|
|
46
|
+
*/
|
|
47
|
+
type ServiceToken<TInstance> = {
|
|
48
|
+
readonly [SERVICE_INSTANCE]?: TInstance;
|
|
49
|
+
} & symbol;
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region ../core/src/tools/tools.types.d.ts
|
|
52
|
+
/** the four facts of the running turn (§4) — everything else a tool needs, its toolset declares */
|
|
53
|
+
type ToolTurnScope = {
|
|
54
|
+
readonly agentUsername: string;
|
|
55
|
+
readonly channelId: string;
|
|
56
|
+
/** provenance for anything a tool records; null on a turn no post triggered */
|
|
57
|
+
readonly triggeringPostId: null | string;
|
|
58
|
+
readonly turnId: string;
|
|
59
|
+
};
|
|
60
|
+
/** §6.2 — the full payload the approver reads; presence of the `approval` hook is what gates a tool (§5) */
|
|
61
|
+
type ToolApprovalPayload = {
|
|
62
|
+
body: string;
|
|
63
|
+
presentation: ApprovalPayloadPresentation;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* A durable record's disclosure (§3.6), returned by the tool that created it; the turn writes the
|
|
67
|
+
* event and the trace lines. `reference` names the record for later reads, e.g. a memory id.
|
|
68
|
+
*/
|
|
69
|
+
type ToolDisclosure = {
|
|
70
|
+
readonly body: string;
|
|
71
|
+
readonly description: string;
|
|
72
|
+
readonly reference: string;
|
|
73
|
+
readonly supersededDescriptions?: readonly string[];
|
|
74
|
+
};
|
|
75
|
+
declare namespace ToolFailure {
|
|
76
|
+
/** the tool body threw — a semantic failure that terminates the turn (§7.1, §7.2) */
|
|
77
|
+
type Exception = {
|
|
78
|
+
kind: 'exception';
|
|
79
|
+
message: string;
|
|
80
|
+
};
|
|
81
|
+
/** the arguments were rejected — returned to the model as the tool result; the turn continues */
|
|
82
|
+
type InvalidArguments = {
|
|
83
|
+
kind: 'invalid-arguments';
|
|
84
|
+
message: string;
|
|
85
|
+
};
|
|
86
|
+
/** execution outlived `timeoutMs` — for a mutation the side effect is unconfirmed (§7.1, §7.2) */
|
|
87
|
+
type Timeout = {
|
|
88
|
+
kind: 'timeout';
|
|
89
|
+
timeoutMs: number;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* The tool committed something whose outcome cannot be established — a send that may or may not
|
|
93
|
+
* have left. The turn ends stating the ambiguity (§7.1); it is never returned to the model,
|
|
94
|
+
* because a model told "unresolved" will try again, which is precisely what must not happen.
|
|
95
|
+
*/
|
|
96
|
+
type Unresolved = {
|
|
97
|
+
kind: 'unresolved';
|
|
98
|
+
message: string;
|
|
99
|
+
};
|
|
100
|
+
/** the model named a tool that does not exist or sits outside its configured set (§6.1, §7.2) */
|
|
101
|
+
type UnknownTool = {
|
|
102
|
+
kind: 'unknown-tool';
|
|
103
|
+
message: string;
|
|
104
|
+
};
|
|
105
|
+
type Any = Exception | InvalidArguments | Timeout | UnknownTool | Unresolved;
|
|
106
|
+
}
|
|
107
|
+
type ToolFailure = ToolFailure.Any;
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region ../core/src/plugins/plugins.errors.d.ts
|
|
110
|
+
/** what `err.invalidArguments` and `err.unresolved` throw; the perimeter wrapper catches it and nothing else */
|
|
111
|
+
declare class PluginToolFailureError extends Error {
|
|
112
|
+
readonly failure: ToolFailure.InvalidArguments | ToolFailure.Unresolved;
|
|
113
|
+
constructor(failure: ToolFailure.InvalidArguments | ToolFailure.Unresolved);
|
|
114
|
+
}
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region ../core/src/plugins/plugins.types.d.ts
|
|
117
|
+
/** what a plugin tool body may return: the text alone, or the text beside a durable record's disclosure (§3.4) */
|
|
118
|
+
type PluginToolOutput = string | {
|
|
119
|
+
readonly disclosure?: ToolDisclosure;
|
|
120
|
+
readonly text: string;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* The two failures a tool body may raise itself — the rest of the taxonomy (§7.1) is the
|
|
124
|
+
* framework's to raise. Each throws; the perimeter wrapper maps the throw into the taxonomy.
|
|
125
|
+
*/
|
|
126
|
+
type PluginToolErr = {
|
|
127
|
+
/** the arguments were rejected — returned to the model as the tool result; the turn continues */
|
|
128
|
+
invalidArguments(message: string): never;
|
|
129
|
+
/** a committed side effect whose outcome cannot be established; the turn ends stating the ambiguity */
|
|
130
|
+
unresolved(message: string): never;
|
|
131
|
+
};
|
|
132
|
+
/** one tool as a plugin declares it: the framework's tool minus `budgetExempt`, returning plain output */
|
|
133
|
+
type PluginToolDeclaration<TContext, TParams extends z.ZodType> = {
|
|
134
|
+
/** present ⇒ the tool always gates (§5); renders the payload the approver reads and cannot decline */
|
|
135
|
+
approval?(args: z.infer<TParams>): ToolApprovalPayload;
|
|
136
|
+
readonly description: string;
|
|
137
|
+
execute(args: z.infer<TParams>, context: TContext): Promisable<PluginToolOutput>;
|
|
138
|
+
readonly parameters: TParams;
|
|
139
|
+
/** §7.2 — whether a timed-out call may be reported to the model as a plain failure; false ends the turn as unconfirmable */
|
|
140
|
+
readonly retryable?: boolean;
|
|
141
|
+
readonly timeoutMs?: number;
|
|
142
|
+
/** §8.1 — the one-line summary beside the name in the status post; absent shows the name alone */
|
|
143
|
+
traceDetail?(args: z.infer<TParams>): string;
|
|
144
|
+
};
|
|
145
|
+
//#endregion
|
|
146
|
+
//#region ../core/src/toolsets/toolsets.types.d.ts
|
|
147
|
+
/** `settings`, `storage`, and `turn` are the context's own keys, so a service may not claim them */
|
|
148
|
+
type ServicesDeclaration = {
|
|
149
|
+
readonly [key: string]: ServiceToken<unknown>;
|
|
150
|
+
} & {
|
|
151
|
+
readonly settings?: never;
|
|
152
|
+
readonly storage?: never;
|
|
153
|
+
readonly turn?: never;
|
|
154
|
+
};
|
|
155
|
+
type CollectionsDeclaration = {
|
|
156
|
+
readonly [key: string]: z.ZodType;
|
|
157
|
+
};
|
|
158
|
+
type EmptyDeclaration = {};
|
|
159
|
+
/** a toolset-scoped handle over one declared storage collection; rows are validated on write and parsed on read */
|
|
160
|
+
type ToolsetCollection<TValue> = {
|
|
161
|
+
delete(key: string): Promise<boolean>;
|
|
162
|
+
get(key: string): Promise<null | TValue>;
|
|
163
|
+
list(): Promise<{
|
|
164
|
+
key: string;
|
|
165
|
+
value: TValue;
|
|
166
|
+
}[]>;
|
|
167
|
+
put(key: string, value: TValue): Promise<void>;
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* What `execute` receives, assembled from exactly what the toolset declared (§4): each service
|
|
171
|
+
* under its own name, `settings` and `storage` only when declared, and always the turn. Reaching
|
|
172
|
+
* anything undeclared is a compile error.
|
|
173
|
+
*/
|
|
174
|
+
type ToolsetContext<TServices extends ServicesDeclaration = EmptyDeclaration, TSettings extends undefined | z.ZodType = undefined, TCollections extends CollectionsDeclaration = EmptyDeclaration> = { readonly [K in keyof TServices]: TServices[K] extends ServiceToken<infer TInstance> ? TInstance : never; } & {
|
|
175
|
+
readonly turn: ToolTurnScope;
|
|
176
|
+
} & (keyof TCollections extends never ? unknown : {
|
|
177
|
+
readonly storage: { readonly [K in keyof TCollections]: ToolsetCollection<z.infer<TCollections[K]>>; };
|
|
178
|
+
}) & (TSettings extends z.ZodType ? {
|
|
179
|
+
readonly settings: z.infer<TSettings>;
|
|
180
|
+
} : unknown);
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/tool.d.ts
|
|
183
|
+
/** what `execute` receives under a config: its settings and storage, the failure raisers, and the four facts of the turn */
|
|
184
|
+
type ToolContextFor<TConfig extends PluginConfig> = ToolsetContext<EmptyDeclaration, TConfig['settings'], TConfig['storage']> & {
|
|
185
|
+
readonly err: PluginToolErr;
|
|
186
|
+
};
|
|
187
|
+
/** the context under the registered config: what every tool file's `execute` receives */
|
|
188
|
+
type ToolContext = ToolContextFor<RegisteredConfig>;
|
|
189
|
+
type PluginTool<TParams extends z.ZodType> = PluginToolDeclaration<ToolContext, TParams>;
|
|
190
|
+
/** identity at runtime; what it is for is typing `args` from `parameters` across the whole declaration */
|
|
191
|
+
declare function defineTool<TParams extends z.ZodType>(tool: PluginTool<TParams>): PluginTool<TParams>;
|
|
192
|
+
//#endregion
|
|
193
|
+
export { PluginToolFailureError as a, ToolTurnScope as c, defineConfig as d, defineTool as i, PluginConfig as l, ToolContext as n, ToolApprovalPayload as o, ToolContextFor as r, ToolDisclosure as s, PluginTool as t, Register as u };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@collegium/sdk",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.1-beta.
|
|
4
|
+
"version": "0.0.1-beta.8",
|
|
5
5
|
"description": "Write a Collegium plugin: declare a toolset with its tools, settings, storage, and skills.",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
7
7
|
"homepage": "https://collegium.sh",
|
|
@@ -21,7 +21,11 @@
|
|
|
21
21
|
"types": "./dist/index.d.ts",
|
|
22
22
|
"default": "./dist/index.js"
|
|
23
23
|
},
|
|
24
|
-
"./package.json": "./package.json"
|
|
24
|
+
"./package.json": "./package.json",
|
|
25
|
+
"./testing": {
|
|
26
|
+
"types": "./dist/testing.d.ts",
|
|
27
|
+
"default": "./dist/testing.js"
|
|
28
|
+
}
|
|
25
29
|
},
|
|
26
30
|
"files": [
|
|
27
31
|
"dist"
|