@opencode-ai/plugin 0.0.0-next-16088 → 0.0.0-next-16092
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/v2/effect/internal/tool.d.ts +177 -0
- package/dist/v2/effect/internal/tool.js +108 -0
- package/dist/v2/effect/tool.d.ts +2 -159
- package/dist/v2/effect/tool.js +2 -114
- package/dist/v2/promise/internal/tool.d.ts +32 -0
- package/dist/v2/promise/internal/tool.js +3 -0
- package/dist/v2/promise/tool.d.ts +2 -34
- package/dist/v2/promise/tool.js +2 -0
- package/package.json +5 -5
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { Agent } from "@opencode-ai/schema/agent";
|
|
2
|
+
import { Session } from "@opencode-ai/schema/session";
|
|
3
|
+
import { SessionMessage } from "@opencode-ai/schema/session-message";
|
|
4
|
+
import type { StandardJSONSchemaV1, StandardSchemaV1 } from "@standard-schema/spec";
|
|
5
|
+
import { Effect, JsonSchema, Schema } from "effect";
|
|
6
|
+
import type { Hooks, Transform } from "../registration.js";
|
|
7
|
+
/** A JSON-compatible value. Tool metadata and encoded outputs must be JSON. */
|
|
8
|
+
export type JsonValue = typeof Schema.Json.Type;
|
|
9
|
+
/** Compact JSON metadata for tool-specific UI and client behavior. */
|
|
10
|
+
export type Metadata = Readonly<Record<string, JsonValue>>;
|
|
11
|
+
export interface Context {
|
|
12
|
+
readonly sessionID: Session.ID;
|
|
13
|
+
readonly agent: Agent.ID;
|
|
14
|
+
readonly messageID: SessionMessage.ID;
|
|
15
|
+
readonly callID: string;
|
|
16
|
+
readonly progress: (update: Progress) => Effect.Effect<void>;
|
|
17
|
+
}
|
|
18
|
+
/** Live replacement metadata for a running tool. */
|
|
19
|
+
export type Progress = Metadata;
|
|
20
|
+
export type StandardSchemaType<Input = unknown, Output = Input> = StandardSchemaV1<Input, Output> & StandardJSONSchemaV1<Input, Output>;
|
|
21
|
+
export type SchemaType<A = unknown> = Schema.Codec<A, any> | StandardSchemaType<any, A> | JsonSchema.JsonSchema;
|
|
22
|
+
type IsAny<A> = 0 extends 1 & A ? true : false;
|
|
23
|
+
export type InputValue<S> = IsAny<S> extends true ? any : S extends Schema.Codec<infer A, any> ? A : S extends StandardSchemaV1<any, infer A> ? A : unknown;
|
|
24
|
+
export type OutputValue<S> = IsAny<S> extends true ? any : S extends Schema.Codec<infer A, any> ? A : S extends StandardSchemaV1<infer A, any> ? A : unknown;
|
|
25
|
+
export type EncodedValue<S> = IsAny<S> extends true ? any : S extends Schema.Codec<any, infer A> ? A : S extends StandardSchemaV1<any, infer A> ? A : unknown;
|
|
26
|
+
type ToolDefinition = {
|
|
27
|
+
readonly name: string;
|
|
28
|
+
readonly description: string;
|
|
29
|
+
readonly inputSchema: JsonSchema.JsonSchema;
|
|
30
|
+
readonly outputSchema?: JsonSchema.JsonSchema;
|
|
31
|
+
};
|
|
32
|
+
declare const Failure_base: Schema.Class<Failure, Schema.TaggedStruct<"LLM.ToolFailure", {
|
|
33
|
+
readonly message: Schema.String;
|
|
34
|
+
readonly error: Schema.optional<Schema.Defect>;
|
|
35
|
+
}>, import("effect/Cause").YieldableError>;
|
|
36
|
+
export declare class Failure extends Failure_base {
|
|
37
|
+
}
|
|
38
|
+
declare const RegistrationError_base: Schema.Class<RegistrationError, Schema.TaggedStruct<"Tool.RegistrationError", {
|
|
39
|
+
readonly name: Schema.String;
|
|
40
|
+
readonly message: Schema.String;
|
|
41
|
+
}>, import("effect/Cause").YieldableError>;
|
|
42
|
+
export declare class RegistrationError extends RegistrationError_base {
|
|
43
|
+
}
|
|
44
|
+
export type Content = {
|
|
45
|
+
readonly type: "text";
|
|
46
|
+
readonly text: string;
|
|
47
|
+
} | {
|
|
48
|
+
readonly type: "file";
|
|
49
|
+
readonly data: string;
|
|
50
|
+
readonly mime: string;
|
|
51
|
+
readonly name?: string;
|
|
52
|
+
};
|
|
53
|
+
/** Model-facing tool content: plain text or non-empty rich content. */
|
|
54
|
+
export type ModelOutput = string | readonly [Content, ...Content[]];
|
|
55
|
+
type BaseTool<Input extends SchemaType<any>> = {
|
|
56
|
+
readonly description: string;
|
|
57
|
+
readonly input: Input;
|
|
58
|
+
};
|
|
59
|
+
export type Response<Output extends SchemaType<any>> = {
|
|
60
|
+
readonly output: OutputValue<Output>;
|
|
61
|
+
readonly content?: ModelOutput;
|
|
62
|
+
readonly metadata?: Metadata;
|
|
63
|
+
};
|
|
64
|
+
export type ContentResponse = {
|
|
65
|
+
readonly content: ModelOutput;
|
|
66
|
+
readonly metadata?: Metadata;
|
|
67
|
+
};
|
|
68
|
+
export type Tool<Input extends SchemaType<any>, Output extends SchemaType<any> | undefined = undefined> = BaseTool<Input> & (Output extends SchemaType<any> ? {
|
|
69
|
+
readonly output: Output;
|
|
70
|
+
readonly execute: (input: InputValue<Input>, context: Context) => Effect.Effect<Response<Output>, Failure>;
|
|
71
|
+
} : {
|
|
72
|
+
readonly output?: undefined;
|
|
73
|
+
readonly execute: (input: InputValue<Input>, context: Context) => Effect.Effect<ContentResponse, Failure>;
|
|
74
|
+
});
|
|
75
|
+
export type Any = BaseTool<any> & {
|
|
76
|
+
readonly output?: SchemaType<any>;
|
|
77
|
+
readonly execute: (input: any, context: Context) => Effect.Effect<Response<any> | ContentResponse, Failure>;
|
|
78
|
+
};
|
|
79
|
+
export declare function make<Input extends SchemaType<any>, Output extends SchemaType<any>>(config: Tool<Input, Output>): Tool<Input, Output>;
|
|
80
|
+
export declare function make<Input extends SchemaType<any>>(config: Tool<Input>): Tool<Input>;
|
|
81
|
+
export declare function make(config: Any): Any;
|
|
82
|
+
export interface RegisterOptions {
|
|
83
|
+
readonly namespace?: string;
|
|
84
|
+
/** Defaults to true. False exposes the tool directly to the provider. */
|
|
85
|
+
readonly codemode?: boolean;
|
|
86
|
+
/** Permission action used for whole-tool visibility filtering. */
|
|
87
|
+
readonly permission?: string;
|
|
88
|
+
}
|
|
89
|
+
export interface Registration {
|
|
90
|
+
readonly tool: Any;
|
|
91
|
+
readonly name: string;
|
|
92
|
+
readonly namespace?: string;
|
|
93
|
+
readonly permission: string;
|
|
94
|
+
}
|
|
95
|
+
export declare const validateName: (name: string) => Effect.Effect<void, never, never> | Effect.Effect<never, RegistrationError, never>;
|
|
96
|
+
export declare const registrationEntries: (tools: Readonly<Record<string, Any>>, options?: RegisterOptions) => Array<Registration & {
|
|
97
|
+
readonly key: string;
|
|
98
|
+
}>;
|
|
99
|
+
export declare const validateNamespace: (namespace: string) => Effect.Effect<void, never, never> | Effect.Effect<never, RegistrationError, never>;
|
|
100
|
+
export declare const toLLMDefinition: (name: string, tool: Any) => ToolDefinition;
|
|
101
|
+
export declare function decodeInput(schema: SchemaType<any>, value: unknown): Effect.Effect<any, Failure>;
|
|
102
|
+
export declare function encodeOutput(schema: SchemaType<any>, value: unknown): Effect.Effect<any, Failure>;
|
|
103
|
+
export interface ToolExecuteBeforeEvent {
|
|
104
|
+
readonly tool: string;
|
|
105
|
+
readonly sessionID: Session.ID;
|
|
106
|
+
readonly agent: Agent.ID;
|
|
107
|
+
readonly messageID: SessionMessage.ID;
|
|
108
|
+
readonly callID: string;
|
|
109
|
+
input: unknown;
|
|
110
|
+
}
|
|
111
|
+
type ToolHookBase = {
|
|
112
|
+
readonly tool: string;
|
|
113
|
+
readonly sessionID: Session.ID;
|
|
114
|
+
readonly agent: Agent.ID;
|
|
115
|
+
readonly messageID: SessionMessage.ID;
|
|
116
|
+
readonly callID: string;
|
|
117
|
+
readonly input: unknown;
|
|
118
|
+
};
|
|
119
|
+
export declare const ExecuteAfterOutcome: Schema.toTaggedUnion<"status", readonly [Schema.Struct<{
|
|
120
|
+
readonly status: Schema.Literal<"completed">;
|
|
121
|
+
readonly content: Schema.NonEmptyArray<Schema.Union<readonly [Schema.Struct<{
|
|
122
|
+
readonly type: Schema.Literal<"text">;
|
|
123
|
+
readonly text: Schema.String;
|
|
124
|
+
}>, Schema.Struct<{
|
|
125
|
+
readonly type: Schema.Literal<"file">;
|
|
126
|
+
readonly uri: Schema.String;
|
|
127
|
+
readonly mime: Schema.String;
|
|
128
|
+
readonly name: Schema.decodeTo<Schema.optional<Schema.toType<Schema.String>>, Schema.optionalKey<Schema.String>, never, never>;
|
|
129
|
+
}>]>>;
|
|
130
|
+
readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>>;
|
|
131
|
+
readonly outputPaths: Schema.optional<Schema.$Array<Schema.String>>;
|
|
132
|
+
}>, Schema.Struct<{
|
|
133
|
+
readonly status: Schema.Literal<"error">;
|
|
134
|
+
readonly error: Schema.Struct<{
|
|
135
|
+
readonly type: Schema.String;
|
|
136
|
+
readonly message: Schema.String;
|
|
137
|
+
}>;
|
|
138
|
+
readonly content: Schema.optional<Schema.NonEmptyArray<Schema.Union<readonly [Schema.Struct<{
|
|
139
|
+
readonly type: Schema.Literal<"text">;
|
|
140
|
+
readonly text: Schema.String;
|
|
141
|
+
}>, Schema.Struct<{
|
|
142
|
+
readonly type: Schema.Literal<"file">;
|
|
143
|
+
readonly uri: Schema.String;
|
|
144
|
+
readonly mime: Schema.String;
|
|
145
|
+
readonly name: Schema.decodeTo<Schema.optional<Schema.toType<Schema.String>>, Schema.optionalKey<Schema.String>, never, never>;
|
|
146
|
+
}>]>>>;
|
|
147
|
+
readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>>;
|
|
148
|
+
readonly outputPaths: Schema.optional<Schema.$Array<Schema.String>>;
|
|
149
|
+
}>]>;
|
|
150
|
+
type Mutable<A> = {
|
|
151
|
+
-readonly [K in keyof A]: A[K];
|
|
152
|
+
};
|
|
153
|
+
type HookOutcome<A extends {
|
|
154
|
+
readonly status: string;
|
|
155
|
+
}> = Omit<Mutable<A>, "status"> & Pick<A, "status">;
|
|
156
|
+
/** The bounded terminal outcome exposed to tool hooks. */
|
|
157
|
+
export type Outcome = typeof ExecuteAfterOutcome.Type extends infer A ? A extends {
|
|
158
|
+
readonly status: string;
|
|
159
|
+
} ? HookOutcome<A> : never : never;
|
|
160
|
+
/**
|
|
161
|
+
* The canonical execution outcome as seen by `execute.after` hooks. Hooks
|
|
162
|
+
* observe bounded model content, optional metadata, and managed output paths;
|
|
163
|
+
* they never observe the raw domain output.
|
|
164
|
+
*/
|
|
165
|
+
export type ToolExecuteAfterEvent = ToolHookBase & Outcome;
|
|
166
|
+
export interface ToolDraft {
|
|
167
|
+
add(name: string, tool: Any, options?: RegisterOptions): void;
|
|
168
|
+
}
|
|
169
|
+
export interface ToolHooks {
|
|
170
|
+
readonly "execute.before": ToolExecuteBeforeEvent;
|
|
171
|
+
readonly "execute.after": ToolExecuteAfterEvent;
|
|
172
|
+
}
|
|
173
|
+
export interface ToolDomain {
|
|
174
|
+
readonly transform: Transform<ToolDraft>;
|
|
175
|
+
readonly hook: Hooks<ToolHooks>;
|
|
176
|
+
}
|
|
177
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Agent } from "@opencode-ai/schema/agent";
|
|
2
|
+
import { LLM } from "@opencode-ai/schema/llm";
|
|
3
|
+
import { Session } from "@opencode-ai/schema/session";
|
|
4
|
+
import { SessionError } from "@opencode-ai/schema/session-error";
|
|
5
|
+
import { SessionMessage } from "@opencode-ai/schema/session-message";
|
|
6
|
+
import { Effect, JsonSchema, Schema } from "effect";
|
|
7
|
+
export class Failure extends Schema.TaggedErrorClass()("LLM.ToolFailure", {
|
|
8
|
+
message: Schema.String,
|
|
9
|
+
error: Schema.optional(Schema.Defect()),
|
|
10
|
+
}) {
|
|
11
|
+
}
|
|
12
|
+
export class RegistrationError extends Schema.TaggedErrorClass()("Tool.RegistrationError", {
|
|
13
|
+
name: Schema.String,
|
|
14
|
+
message: Schema.String,
|
|
15
|
+
}) {
|
|
16
|
+
}
|
|
17
|
+
export function make(config) {
|
|
18
|
+
return config;
|
|
19
|
+
}
|
|
20
|
+
export const validateName = (name) => /^[A-Za-z][A-Za-z0-9_-]{0,63}$/.test(name)
|
|
21
|
+
? Effect.void
|
|
22
|
+
: Effect.fail(new RegistrationError({ name, message: `Invalid tool name: ${name}` }));
|
|
23
|
+
export const registrationEntries = (tools, options) => Object.entries(tools).map(([name, tool]) => {
|
|
24
|
+
const normalized = name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
25
|
+
const key = options?.namespace === undefined ? normalized : `${options.namespace.replaceAll(".", "_")}_${normalized}`;
|
|
26
|
+
return {
|
|
27
|
+
key,
|
|
28
|
+
name: normalized,
|
|
29
|
+
namespace: options?.namespace,
|
|
30
|
+
tool,
|
|
31
|
+
permission: options?.permission ?? key,
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
export const validateNamespace = (namespace) => namespace.split(".").every((segment) => /^[A-Za-z][A-Za-z0-9_-]{0,63}$/.test(segment))
|
|
35
|
+
? Effect.void
|
|
36
|
+
: Effect.fail(new RegistrationError({ name: namespace, message: `Invalid tool namespace: ${JSON.stringify(namespace)}` }));
|
|
37
|
+
export const toLLMDefinition = (name, tool) => ({
|
|
38
|
+
name,
|
|
39
|
+
description: tool.description,
|
|
40
|
+
inputSchema: inputJsonSchema(tool.input),
|
|
41
|
+
...(tool.output === undefined ? {} : { outputSchema: outputJsonSchema(tool.output) }),
|
|
42
|
+
});
|
|
43
|
+
// Schema interpretation
|
|
44
|
+
export function decodeInput(schema, value) {
|
|
45
|
+
if (Schema.isSchema(schema))
|
|
46
|
+
return Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError((error) => new Failure({ message: `Invalid tool input: ${error.message}` })));
|
|
47
|
+
if (isStandardSchema(schema))
|
|
48
|
+
return validateStandard(schema, value, "Invalid tool input");
|
|
49
|
+
return Effect.succeed(value);
|
|
50
|
+
}
|
|
51
|
+
export function encodeOutput(schema, value) {
|
|
52
|
+
if (Schema.isSchema(schema))
|
|
53
|
+
return Schema.encodeEffect(schema)(value).pipe(Effect.mapError((error) => new Failure({ message: `Tool returned an invalid value for its output schema: ${error.message}` })));
|
|
54
|
+
if (isStandardSchema(schema))
|
|
55
|
+
return validateStandard(schema, value, "Tool returned an invalid value for its output schema");
|
|
56
|
+
return Schema.decodeUnknownEffect(Schema.Json)(value).pipe(Effect.mapError((error) => new Failure({ message: `Tool returned a non-JSON value for its output schema: ${error.message}` })));
|
|
57
|
+
}
|
|
58
|
+
function isStandardSchema(schema) {
|
|
59
|
+
return "~standard" in schema;
|
|
60
|
+
}
|
|
61
|
+
function validateStandard(schema, value, prefix) {
|
|
62
|
+
return Effect.gen(function* () {
|
|
63
|
+
const pending = yield* Effect.try({
|
|
64
|
+
try: () => schema["~standard"].validate(value),
|
|
65
|
+
catch: (error) => standardFailure(prefix, error),
|
|
66
|
+
});
|
|
67
|
+
const result = pending instanceof Promise
|
|
68
|
+
? yield* Effect.tryPromise({ try: () => pending, catch: (error) => standardFailure(prefix, error) })
|
|
69
|
+
: pending;
|
|
70
|
+
if (result.issues)
|
|
71
|
+
return yield* Effect.fail(new Failure({ message: `${prefix}: ${result.issues.map((issue) => issue.message).join(", ")}` }));
|
|
72
|
+
return result.value;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function standardFailure(prefix, error) {
|
|
76
|
+
return new Failure({ message: `${prefix}: ${error instanceof Error ? error.message : String(error)}` });
|
|
77
|
+
}
|
|
78
|
+
function inputJsonSchema(schema) {
|
|
79
|
+
if (isStandardSchema(schema))
|
|
80
|
+
return schema["~standard"].jsonSchema.input({ target: "draft-2020-12" });
|
|
81
|
+
return Schema.isSchema(schema) ? toJsonSchema(schema) : schema;
|
|
82
|
+
}
|
|
83
|
+
function outputJsonSchema(schema) {
|
|
84
|
+
if (isStandardSchema(schema))
|
|
85
|
+
return schema["~standard"].jsonSchema.output({ target: "draft-2020-12" });
|
|
86
|
+
return Schema.isSchema(schema) ? toJsonSchema(schema) : schema;
|
|
87
|
+
}
|
|
88
|
+
function toJsonSchema(schema) {
|
|
89
|
+
const document = Schema.toJsonSchemaDocument(schema);
|
|
90
|
+
if (Object.keys(document.definitions).length === 0)
|
|
91
|
+
return document.schema;
|
|
92
|
+
return { ...document.schema, $defs: document.definitions };
|
|
93
|
+
}
|
|
94
|
+
export const ExecuteAfterOutcome = Schema.Union([
|
|
95
|
+
Schema.Struct({
|
|
96
|
+
status: Schema.Literal("completed"),
|
|
97
|
+
content: Schema.NonEmptyArray(LLM.ToolContent),
|
|
98
|
+
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Json)),
|
|
99
|
+
outputPaths: Schema.optional(Schema.Array(Schema.String)),
|
|
100
|
+
}),
|
|
101
|
+
Schema.Struct({
|
|
102
|
+
status: Schema.Literal("error"),
|
|
103
|
+
error: SessionError.Error,
|
|
104
|
+
content: Schema.optional(Schema.NonEmptyArray(LLM.ToolContent)),
|
|
105
|
+
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Json)),
|
|
106
|
+
outputPaths: Schema.optional(Schema.Array(Schema.String)),
|
|
107
|
+
}),
|
|
108
|
+
]).pipe(Schema.toTaggedUnion("status"));
|
package/dist/v2/effect/tool.d.ts
CHANGED
|
@@ -1,159 +1,2 @@
|
|
|
1
|
-
export * as Tool from "./tool.js";
|
|
2
|
-
|
|
3
|
-
import type { LLM } from "@opencode-ai/schema/llm";
|
|
4
|
-
import { Session } from "@opencode-ai/schema/session";
|
|
5
|
-
import { SessionMessage } from "@opencode-ai/schema/session-message";
|
|
6
|
-
import type { StandardJSONSchemaV1, StandardSchemaV1 } from "@standard-schema/spec";
|
|
7
|
-
import { Effect, JsonSchema, Schema } from "effect";
|
|
8
|
-
import type { Hooks, Transform } from "./registration.js";
|
|
9
|
-
export interface Context {
|
|
10
|
-
readonly sessionID: Session.ID;
|
|
11
|
-
readonly agent: Agent.ID;
|
|
12
|
-
readonly messageID: SessionMessage.ID;
|
|
13
|
-
readonly callID: string;
|
|
14
|
-
readonly progress: (update: Progress) => Effect.Effect<void>;
|
|
15
|
-
}
|
|
16
|
-
export interface Progress {
|
|
17
|
-
readonly structured: Readonly<Record<string, unknown>>;
|
|
18
|
-
readonly content?: ReadonlyArray<Content>;
|
|
19
|
-
}
|
|
20
|
-
export type StandardSchemaType<Input = unknown, Output = Input> = StandardSchemaV1<Input, Output> & StandardJSONSchemaV1<Input, Output>;
|
|
21
|
-
export type SchemaType<A> = Schema.Codec<A, any> | StandardSchemaType<any, A>;
|
|
22
|
-
type IsAny<A> = 0 extends 1 & A ? true : false;
|
|
23
|
-
export type InputValue<S> = IsAny<S> extends true ? any : S extends Schema.Codec<infer A, any> ? A : S extends StandardSchemaV1<any, infer A> ? A : never;
|
|
24
|
-
export type OutputValue<S> = IsAny<S> extends true ? any : S extends Schema.Codec<infer A, any> ? A : S extends StandardSchemaV1<infer A, any> ? A : never;
|
|
25
|
-
export type EncodedValue<S> = IsAny<S> extends true ? any : S extends Schema.Codec<any, infer A> ? A : S extends StandardSchemaV1<any, infer A> ? A : never;
|
|
26
|
-
type ToolDefinition = {
|
|
27
|
-
readonly name: string;
|
|
28
|
-
readonly description: string;
|
|
29
|
-
readonly inputSchema: JsonSchema.JsonSchema;
|
|
30
|
-
readonly outputSchema?: JsonSchema.JsonSchema;
|
|
31
|
-
};
|
|
32
|
-
type ToolCall = {
|
|
33
|
-
readonly input: unknown;
|
|
34
|
-
readonly [key: string]: unknown;
|
|
35
|
-
};
|
|
36
|
-
type ToolResultValue = {
|
|
37
|
-
readonly type: "json";
|
|
38
|
-
readonly value: unknown;
|
|
39
|
-
} | {
|
|
40
|
-
readonly type: "text";
|
|
41
|
-
readonly value: unknown;
|
|
42
|
-
} | {
|
|
43
|
-
readonly type: "error";
|
|
44
|
-
readonly value: unknown;
|
|
45
|
-
} | {
|
|
46
|
-
readonly type: "content";
|
|
47
|
-
readonly value: ReadonlyArray<LLM.ToolContent>;
|
|
48
|
-
};
|
|
49
|
-
type ToolOutput = {
|
|
50
|
-
readonly structured: unknown;
|
|
51
|
-
readonly content: ReadonlyArray<LLM.ToolContent>;
|
|
52
|
-
};
|
|
53
|
-
declare const Failure_base: Schema.Class<Failure, Schema.TaggedStruct<"LLM.ToolFailure", {
|
|
54
|
-
readonly message: Schema.String;
|
|
55
|
-
readonly error: Schema.optional<Schema.Defect>;
|
|
56
|
-
readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>;
|
|
57
|
-
}>, import("effect/Cause").YieldableError>;
|
|
58
|
-
export declare class Failure extends Failure_base {
|
|
59
|
-
}
|
|
60
|
-
declare const RegistrationError_base: Schema.Class<RegistrationError, Schema.TaggedStruct<"Tool.RegistrationError", {
|
|
61
|
-
readonly name: Schema.String;
|
|
62
|
-
readonly message: Schema.String;
|
|
63
|
-
}>, import("effect/Cause").YieldableError>;
|
|
64
|
-
export declare class RegistrationError extends RegistrationError_base {
|
|
65
|
-
}
|
|
66
|
-
export type Content = {
|
|
67
|
-
readonly type: "text";
|
|
68
|
-
readonly text: string;
|
|
69
|
-
} | {
|
|
70
|
-
readonly type: "file";
|
|
71
|
-
readonly data: string;
|
|
72
|
-
readonly mime: string;
|
|
73
|
-
readonly name?: string;
|
|
74
|
-
};
|
|
75
|
-
export type Definition<Input extends SchemaType<any>, Structured extends SchemaType<any>, Output extends SchemaType<any> = any> = {
|
|
76
|
-
readonly description: string;
|
|
77
|
-
readonly input: Input;
|
|
78
|
-
readonly output: Output;
|
|
79
|
-
readonly structured?: Structured;
|
|
80
|
-
readonly permission?: string;
|
|
81
|
-
readonly toStructuredOutput?: (input: {
|
|
82
|
-
readonly input: InputValue<Input>;
|
|
83
|
-
readonly output: EncodedValue<Output>;
|
|
84
|
-
}) => OutputValue<Structured>;
|
|
85
|
-
readonly execute: (input: InputValue<Input>, context: Context) => Effect.Effect<OutputValue<Output>, Failure>;
|
|
86
|
-
readonly toModelOutput?: (input: {
|
|
87
|
-
readonly input: InputValue<Input>;
|
|
88
|
-
readonly output: EncodedValue<Output>;
|
|
89
|
-
}) => ReadonlyArray<Content>;
|
|
90
|
-
};
|
|
91
|
-
export type DynamicOutput = {
|
|
92
|
-
readonly structured: unknown;
|
|
93
|
-
readonly content: ReadonlyArray<Content>;
|
|
94
|
-
};
|
|
95
|
-
/**
|
|
96
|
-
* Config for a tool whose input shape is a raw JSON Schema not known at compile
|
|
97
|
-
* time (MCP servers, plugin manifests). Input is passed through as `unknown`;
|
|
98
|
-
* `execute` returns the already-projected structured value and model content.
|
|
99
|
-
*/
|
|
100
|
-
export type DynamicDefinition = {
|
|
101
|
-
readonly description: string;
|
|
102
|
-
readonly jsonSchema: JsonSchema.JsonSchema;
|
|
103
|
-
readonly outputSchema?: JsonSchema.JsonSchema;
|
|
104
|
-
readonly permission?: string;
|
|
105
|
-
readonly execute: (input: unknown, context: Context) => Effect.Effect<DynamicOutput, Failure>;
|
|
106
|
-
};
|
|
107
|
-
export type AnyTool = Definition<any, any> | DynamicDefinition;
|
|
108
|
-
export declare function make<Input extends SchemaType<any>, Output extends SchemaType<any>, Structured extends SchemaType<any> = Output>(config: Definition<Input, Structured, Output>): Definition<Input, Structured, Output>;
|
|
109
|
-
export declare function make(config: DynamicDefinition): DynamicDefinition;
|
|
110
|
-
export declare function make(config: AnyTool): AnyTool;
|
|
111
|
-
export declare const validateName: (name: string) => Effect.Effect<void, never, never> | Effect.Effect<never, RegistrationError, never>;
|
|
112
|
-
export declare const registrationEntries: (tools: Readonly<Record<string, AnyTool>>, namespace?: string) => {
|
|
113
|
-
key: string;
|
|
114
|
-
name: string;
|
|
115
|
-
namespace: string | undefined;
|
|
116
|
-
tool: AnyTool;
|
|
117
|
-
}[];
|
|
118
|
-
export declare const validateNamespace: (namespace: string) => Effect.Effect<void, never, never> | Effect.Effect<never, RegistrationError, never>;
|
|
119
|
-
export declare const withPermission: <T extends AnyTool>(tool: T, permission: string) => Omit<T, "permission"> & {
|
|
120
|
-
readonly permission: string;
|
|
121
|
-
};
|
|
122
|
-
export declare const permission: (tool: AnyTool, name: string) => string;
|
|
123
|
-
export declare const definition: (name: string, tool: AnyTool) => ToolDefinition;
|
|
124
|
-
export declare const settle: (tool: AnyTool, call: ToolCall, context: Context) => Effect.Effect<ToolOutput, Failure>;
|
|
125
|
-
export interface ToolExecuteBeforeEvent {
|
|
126
|
-
readonly tool: string;
|
|
127
|
-
readonly sessionID: Session.ID;
|
|
128
|
-
readonly agent: Agent.ID;
|
|
129
|
-
readonly messageID: SessionMessage.ID;
|
|
130
|
-
readonly callID: string;
|
|
131
|
-
input: unknown;
|
|
132
|
-
}
|
|
133
|
-
export interface ToolExecuteAfterEvent {
|
|
134
|
-
readonly tool: string;
|
|
135
|
-
readonly sessionID: Session.ID;
|
|
136
|
-
readonly agent: Agent.ID;
|
|
137
|
-
readonly messageID: SessionMessage.ID;
|
|
138
|
-
readonly callID: string;
|
|
139
|
-
readonly input: unknown;
|
|
140
|
-
result: ToolResultValue;
|
|
141
|
-
output?: ToolOutput;
|
|
142
|
-
outputPaths?: ReadonlyArray<string>;
|
|
143
|
-
}
|
|
144
|
-
export interface RegisterOptions {
|
|
145
|
-
readonly namespace?: string;
|
|
146
|
-
/** Defaults to true. False exposes the tool directly to the provider. */
|
|
147
|
-
readonly codemode?: boolean;
|
|
148
|
-
}
|
|
149
|
-
export interface ToolDraft {
|
|
150
|
-
add(name: string, tool: AnyTool, options?: RegisterOptions): void;
|
|
151
|
-
}
|
|
152
|
-
export interface ToolHooks {
|
|
153
|
-
readonly "execute.before": ToolExecuteBeforeEvent;
|
|
154
|
-
readonly "execute.after": ToolExecuteAfterEvent;
|
|
155
|
-
}
|
|
156
|
-
export interface ToolDomain {
|
|
157
|
-
readonly transform: Transform<ToolDraft>;
|
|
158
|
-
readonly hook: Hooks<ToolHooks>;
|
|
159
|
-
}
|
|
1
|
+
export * as Tool from "./internal/tool.js";
|
|
2
|
+
export * from "./internal/tool.js";
|
package/dist/v2/effect/tool.js
CHANGED
|
@@ -1,114 +1,2 @@
|
|
|
1
|
-
export * as Tool from "./tool.js";
|
|
2
|
-
|
|
3
|
-
import { Session } from "@opencode-ai/schema/session";
|
|
4
|
-
import { SessionMessage } from "@opencode-ai/schema/session-message";
|
|
5
|
-
import { Effect, JsonSchema, Schema } from "effect";
|
|
6
|
-
export class Failure extends Schema.TaggedErrorClass()("LLM.ToolFailure", {
|
|
7
|
-
message: Schema.String,
|
|
8
|
-
error: Schema.optional(Schema.Defect()),
|
|
9
|
-
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
|
|
10
|
-
}) {
|
|
11
|
-
}
|
|
12
|
-
export class RegistrationError extends Schema.TaggedErrorClass()("Tool.RegistrationError", {
|
|
13
|
-
name: Schema.String,
|
|
14
|
-
message: Schema.String,
|
|
15
|
-
}) {
|
|
16
|
-
}
|
|
17
|
-
export function make(config) {
|
|
18
|
-
return config;
|
|
19
|
-
}
|
|
20
|
-
function toModelContent(part) {
|
|
21
|
-
if (part.type === "text")
|
|
22
|
-
return { type: "text", text: part.text };
|
|
23
|
-
return { type: "file", uri: `data:${part.mime};base64,${part.data}`, mime: part.mime, name: part.name };
|
|
24
|
-
}
|
|
25
|
-
export const validateName = (name) => /^[A-Za-z][A-Za-z0-9_-]{0,63}$/.test(name)
|
|
26
|
-
? Effect.void
|
|
27
|
-
: Effect.fail(new RegistrationError({ name, message: `Invalid tool name: ${name}` }));
|
|
28
|
-
export const registrationEntries = (tools, namespace) => Object.entries(tools).map(([name, tool]) => {
|
|
29
|
-
const normalized = name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
30
|
-
return {
|
|
31
|
-
key: namespace === undefined ? normalized : `${namespace.replaceAll(".", "_")}_${normalized}`,
|
|
32
|
-
name: normalized,
|
|
33
|
-
namespace,
|
|
34
|
-
tool,
|
|
35
|
-
};
|
|
36
|
-
});
|
|
37
|
-
export const validateNamespace = (namespace) => namespace.split(".").every((segment) => /^[A-Za-z][A-Za-z0-9_-]{0,63}$/.test(segment))
|
|
38
|
-
? Effect.void
|
|
39
|
-
: Effect.fail(new RegistrationError({ name: namespace, message: `Invalid tool namespace: ${JSON.stringify(namespace)}` }));
|
|
40
|
-
export const withPermission = (tool, permission) => ({ ...tool, permission });
|
|
41
|
-
export const permission = (tool, name) => tool.permission ?? name;
|
|
42
|
-
export const definition = (name, tool) => "jsonSchema" in tool
|
|
43
|
-
? {
|
|
44
|
-
name,
|
|
45
|
-
description: tool.description,
|
|
46
|
-
inputSchema: tool.jsonSchema,
|
|
47
|
-
outputSchema: tool.outputSchema,
|
|
48
|
-
}
|
|
49
|
-
: {
|
|
50
|
-
name,
|
|
51
|
-
description: tool.description,
|
|
52
|
-
inputSchema: inputJsonSchema(tool.input),
|
|
53
|
-
outputSchema: outputJsonSchema(tool.structured ?? tool.output),
|
|
54
|
-
};
|
|
55
|
-
export const settle = (tool, call, context) => Effect.gen(function* () {
|
|
56
|
-
if ("jsonSchema" in tool) {
|
|
57
|
-
const output = yield* tool.execute(call.input, context);
|
|
58
|
-
return { structured: output.structured, content: output.content.map(toModelContent) };
|
|
59
|
-
}
|
|
60
|
-
const input = yield* decodeInput(tool.input, call.input);
|
|
61
|
-
const value = yield* tool.execute(input, context);
|
|
62
|
-
const output = yield* encodeOutput(tool.output, value);
|
|
63
|
-
const structured = tool.structured && tool.toStructuredOutput
|
|
64
|
-
? yield* encodeOutput(tool.structured, tool.toStructuredOutput({ input, output }))
|
|
65
|
-
: output;
|
|
66
|
-
return {
|
|
67
|
-
structured,
|
|
68
|
-
content: tool.toModelOutput?.({ input, output }).map(toModelContent) ??
|
|
69
|
-
(typeof output === "string" ? [{ type: "text", text: output }] : []),
|
|
70
|
-
};
|
|
71
|
-
});
|
|
72
|
-
function decodeInput(schema, value) {
|
|
73
|
-
if (Schema.isSchema(schema))
|
|
74
|
-
return Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError((error) => new Failure({ message: `Invalid tool input: ${error.message}` })));
|
|
75
|
-
return validateStandard(schema, value, "Invalid tool input");
|
|
76
|
-
}
|
|
77
|
-
function encodeOutput(schema, value) {
|
|
78
|
-
if (Schema.isSchema(schema))
|
|
79
|
-
return Schema.encodeEffect(schema)(value).pipe(Effect.mapError((error) => new Failure({ message: `Tool returned an invalid value for its output schema: ${error.message}` })));
|
|
80
|
-
return validateStandard(schema, value, "Tool returned an invalid value for its output schema");
|
|
81
|
-
}
|
|
82
|
-
function validateStandard(schema, value, prefix) {
|
|
83
|
-
return Effect.gen(function* () {
|
|
84
|
-
const pending = yield* Effect.try({
|
|
85
|
-
try: () => schema["~standard"].validate(value),
|
|
86
|
-
catch: (error) => standardFailure(prefix, error),
|
|
87
|
-
});
|
|
88
|
-
const result = pending instanceof Promise
|
|
89
|
-
? yield* Effect.tryPromise({ try: () => pending, catch: (error) => standardFailure(prefix, error) })
|
|
90
|
-
: pending;
|
|
91
|
-
if (result.issues)
|
|
92
|
-
return yield* Effect.fail(new Failure({ message: `${prefix}: ${result.issues.map((issue) => issue.message).join(", ")}` }));
|
|
93
|
-
return result.value;
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
function standardFailure(prefix, error) {
|
|
97
|
-
return new Failure({ message: `${prefix}: ${error instanceof Error ? error.message : String(error)}` });
|
|
98
|
-
}
|
|
99
|
-
function inputJsonSchema(schema) {
|
|
100
|
-
if (!Schema.isSchema(schema))
|
|
101
|
-
return schema["~standard"].jsonSchema.input({ target: "draft-2020-12" });
|
|
102
|
-
return toJsonSchema(schema);
|
|
103
|
-
}
|
|
104
|
-
function outputJsonSchema(schema) {
|
|
105
|
-
if (!Schema.isSchema(schema))
|
|
106
|
-
return schema["~standard"].jsonSchema.output({ target: "draft-2020-12" });
|
|
107
|
-
return toJsonSchema(schema);
|
|
108
|
-
}
|
|
109
|
-
function toJsonSchema(schema) {
|
|
110
|
-
const document = Schema.toJsonSchemaDocument(schema);
|
|
111
|
-
if (Object.keys(document.definitions).length === 0)
|
|
112
|
-
return document.schema;
|
|
113
|
-
return { ...document.schema, $defs: document.definitions };
|
|
114
|
-
}
|
|
1
|
+
export * as Tool from "./internal/tool.js";
|
|
2
|
+
export * from "./internal/tool.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Hooks, Transform } from "../registration.js";
|
|
2
|
+
export type Context = Omit<import("../../effect/internal/tool.js").Context, "progress"> & {
|
|
3
|
+
readonly progress: (update: import("../../effect/internal/tool.js").Progress) => Promise<void>;
|
|
4
|
+
};
|
|
5
|
+
export type SchemaType<A> = import("../../effect/internal/tool.js").SchemaType<A>;
|
|
6
|
+
export type Content = import("../../effect/internal/tool.js").Content;
|
|
7
|
+
export type Metadata = import("../../effect/internal/tool.js").Metadata;
|
|
8
|
+
export type ModelOutput = import("../../effect/internal/tool.js").ModelOutput;
|
|
9
|
+
export type Tool<Input extends SchemaType<any>, Output extends SchemaType<any> | undefined = undefined> = Omit<import("../../effect/internal/tool.js").Tool<Input, Output>, "execute"> & {
|
|
10
|
+
readonly execute: (input: import("../../effect/internal/tool.js").InputValue<Input>, context: Context) => Promise<Output extends SchemaType<any> ? import("../../effect/internal/tool.js").Response<Output> : import("../../effect/internal/tool.js").ContentResponse>;
|
|
11
|
+
};
|
|
12
|
+
export type Any = Omit<import("../../effect/internal/tool.js").Any, "execute"> & {
|
|
13
|
+
readonly execute: (input: any, context: Context) => Promise<import("../../effect/internal/tool.js").Response<any> | import("../../effect/internal/tool.js").ContentResponse>;
|
|
14
|
+
};
|
|
15
|
+
export declare function make<Input extends SchemaType<any>, Output extends SchemaType<any>>(tool: Tool<Input, Output>): Tool<Input, Output>;
|
|
16
|
+
export declare function make<Input extends SchemaType<any>>(tool: Tool<Input>): Tool<Input>;
|
|
17
|
+
export declare function make(tool: Any): Any;
|
|
18
|
+
export type ToolExecuteBeforeEvent = import("../../effect/internal/tool.js").ToolExecuteBeforeEvent;
|
|
19
|
+
export type ToolExecuteAfterEvent = import("../../effect/internal/tool.js").ToolExecuteAfterEvent;
|
|
20
|
+
export type RegisterOptions = import("../../effect/internal/tool.js").RegisterOptions;
|
|
21
|
+
export interface ToolDraft {
|
|
22
|
+
add<Input extends SchemaType<any>, Output extends SchemaType<any>>(name: string, tool: Tool<Input, Output>, options?: RegisterOptions): void;
|
|
23
|
+
add<Input extends SchemaType<any>>(name: string, tool: Tool<Input>, options?: RegisterOptions): void;
|
|
24
|
+
}
|
|
25
|
+
export interface ToolHooks {
|
|
26
|
+
readonly "execute.before": ToolExecuteBeforeEvent;
|
|
27
|
+
readonly "execute.after": ToolExecuteAfterEvent;
|
|
28
|
+
}
|
|
29
|
+
export interface ToolDomain {
|
|
30
|
+
readonly transform: Transform<ToolDraft>;
|
|
31
|
+
readonly hook: Hooks<ToolHooks>;
|
|
32
|
+
}
|
|
@@ -1,34 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export type Context = Omit<Tool.Context, "progress"> & {
|
|
4
|
-
readonly progress: (update: Tool.Progress) => Promise<void>;
|
|
5
|
-
};
|
|
6
|
-
export type SchemaType<A> = Tool.SchemaType<A>;
|
|
7
|
-
export type Content = Tool.Content;
|
|
8
|
-
export type DynamicOutput = Tool.DynamicOutput;
|
|
9
|
-
export type Definition<Input extends SchemaType<any>, Output extends SchemaType<any>, Structured extends SchemaType<any> = Output> = Omit<Tool.Definition<Input, Structured, Output>, "execute" | "permission"> & {
|
|
10
|
-
readonly name: string;
|
|
11
|
-
readonly options?: RegisterOptions;
|
|
12
|
-
readonly execute: (input: Tool.InputValue<Input>, context: Context) => Promise<Tool.OutputValue<Output>>;
|
|
13
|
-
};
|
|
14
|
-
export type DynamicDefinition = Omit<Tool.DynamicDefinition, "execute" | "permission"> & {
|
|
15
|
-
readonly name: string;
|
|
16
|
-
readonly options?: RegisterOptions;
|
|
17
|
-
readonly execute: (input: unknown, context: Context) => Promise<DynamicOutput>;
|
|
18
|
-
};
|
|
19
|
-
export type AnyTool = Definition<any, any, any> | DynamicDefinition;
|
|
20
|
-
export type ToolExecuteBeforeEvent = Tool.ToolExecuteBeforeEvent;
|
|
21
|
-
export type ToolExecuteAfterEvent = Tool.ToolExecuteAfterEvent;
|
|
22
|
-
export type RegisterOptions = Tool.RegisterOptions;
|
|
23
|
-
export interface ToolDraft {
|
|
24
|
-
add<Input extends SchemaType<any>, Output extends SchemaType<any>, Structured extends SchemaType<any> = Output>(tool: Definition<Input, Output, Structured>): void;
|
|
25
|
-
add(tool: DynamicDefinition): void;
|
|
26
|
-
}
|
|
27
|
-
export interface ToolHooks {
|
|
28
|
-
readonly "execute.before": ToolExecuteBeforeEvent;
|
|
29
|
-
readonly "execute.after": ToolExecuteAfterEvent;
|
|
30
|
-
}
|
|
31
|
-
export interface ToolDomain {
|
|
32
|
-
readonly transform: Transform<ToolDraft>;
|
|
33
|
-
readonly hook: Hooks<ToolHooks>;
|
|
34
|
-
}
|
|
1
|
+
export * as Tool from "./internal/tool.js";
|
|
2
|
+
export * from "./internal/tool.js";
|
package/dist/v2/promise/tool.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@opencode-ai/plugin",
|
|
4
|
-
"version": "0.0.0-next-
|
|
4
|
+
"version": "0.0.0-next-16092",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"scripts": {
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
],
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@ai-sdk/provider": "3.0.8",
|
|
55
|
-
"@opencode-ai/ai": "0.0.0-next-
|
|
56
|
-
"@opencode-ai/client": "0.0.0-next-
|
|
57
|
-
"@opencode-ai/schema": "0.0.0-next-
|
|
58
|
-
"@opencode-ai/sdk": "0.0.0-next-
|
|
55
|
+
"@opencode-ai/ai": "0.0.0-next-16092",
|
|
56
|
+
"@opencode-ai/client": "0.0.0-next-16092",
|
|
57
|
+
"@opencode-ai/schema": "0.0.0-next-16092",
|
|
58
|
+
"@opencode-ai/sdk": "0.0.0-next-16092",
|
|
59
59
|
"@standard-schema/spec": "^1.1.0",
|
|
60
60
|
"effect": "4.0.0-beta.98",
|
|
61
61
|
"zod": "4.1.8"
|