@codeworksh/plugin 0.3.0-canary.67.1.g251f0966 → 0.3.0-canary.70.1.g64a3527d

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.
@@ -3,7 +3,7 @@ import { Schema } from "effect";
3
3
  /**
4
4
  * The identifiers that cross the plugin boundary.
5
5
  *
6
- * A plugin reads a session id off its context and a message id off every tool call, so both
6
+ * A plugin reads a session and thread id off its context and a message id off every tool call, so both
7
7
  * brands have to be the ones the harness itself mints -- a structurally identical brand declared
8
8
  * twice is two types, and a plugin would have to cast to hand either back. They live here, in the
9
9
  * package both sides depend on, rather than being re-declared on each side.
@@ -13,6 +13,14 @@ declare const SessionID: Schema.brand<Schema.String, "Session.ID"> & {
13
13
  create: () => string & import("effect/Brand").Brand<"Session.ID">;
14
14
  };
15
15
  type SessionID = typeof SessionID.Type;
16
+ /**
17
+ * Thread identity: one linear transcript inside a session. Every session has a `main` thread;
18
+ * forks add more. Also the provider session and prompt-cache key, so it is fresh per thread.
19
+ */
20
+ declare const ThreadID: Schema.brand<Schema.String, "Thread.ID"> & {
21
+ create: () => string & import("effect/Brand").Brand<"Thread.ID">;
22
+ };
23
+ type ThreadID = typeof ThreadID.Type;
16
24
  /**
17
25
  * A conversation message id.
18
26
  *
@@ -39,5 +47,5 @@ declare const MessageID: Schema.brand<Schema.String, "Message.ID"> & {
39
47
  };
40
48
  type MessageID = typeof MessageID.Type;
41
49
  //#endregion
42
- export { SessionID as n, MessageID as t };
43
- //# sourceMappingURL=ids-CHjmAdTc.d.mts.map
50
+ export { SessionID as n, ThreadID as r, MessageID as t };
51
+ //# sourceMappingURL=ids-CpPeP5Ks.d.mts.map
package/ids.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as SessionID, t as MessageID } from "./ids-CHjmAdTc.mjs";
2
- export { MessageID, SessionID };
1
+ import { n as SessionID, r as ThreadID, t as MessageID } from "./ids-CpPeP5Ks.mjs";
2
+ export { MessageID, SessionID, ThreadID };
package/ids.mjs CHANGED
@@ -5,7 +5,7 @@ import { uuidv7 } from "uuidv7";
5
5
  /**
6
6
  * The identifiers that cross the plugin boundary.
7
7
  *
8
- * A plugin reads a session id off its context and a message id off every tool call, so both
8
+ * A plugin reads a session and thread id off its context and a message id off every tool call, so both
9
9
  * brands have to be the ones the harness itself mints -- a structurally identical brand declared
10
10
  * twice is two types, and a plugin would have to cast to hand either back. They live here, in the
11
11
  * package both sides depend on, rather than being re-declared on each side.
@@ -19,6 +19,11 @@ const SessionID = Schema.String.check(Schema.isStartingWith("ses")).pipe(Schema.
19
19
  create: () => schema.make("ses_" + uuidv7())
20
20
  })));
21
21
  /**
22
+ * Thread identity: one linear transcript inside a session. Every session has a `main` thread;
23
+ * forks add more. Also the provider session and prompt-cache key, so it is fresh per thread.
24
+ */
25
+ const ThreadID = Schema.String.check(Schema.isStartingWith("thr")).pipe(Schema.brand("Thread.ID"), withStatics((schema) => ({ create: () => schema.make("thr_" + uuidv7()) })));
26
+ /**
22
27
  * A conversation message id.
23
28
  *
24
29
  * Deliberately unprefixed. aikit mints assistant message ids itself, as bare
@@ -43,6 +48,6 @@ const MessageID = Schema.String.pipe(Schema.brand("Message.ID"), withStatics((sc
43
48
  from: (id) => schema.make(id)
44
49
  })));
45
50
  //#endregion
46
- export { MessageID, SessionID };
51
+ export { MessageID, SessionID, ThreadID };
47
52
 
48
53
  //# sourceMappingURL=ids.mjs.map
package/ids.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ids.mjs","names":[],"sources":["../../src/ids.ts"],"sourcesContent":["import { Schema } from \"effect\";\nimport { uuidv7 } from \"uuidv7\";\nimport { withStatics } from \"./schema.ts\";\n\n/**\n * The identifiers that cross the plugin boundary.\n *\n * A plugin reads a session id off its context and a message id off every tool call, so both\n * brands have to be the ones the harness itself mints -- a structurally identical brand declared\n * twice is two types, and a plugin would have to cast to hand either back. They live here, in the\n * package both sides depend on, rather than being re-declared on each side.\n */\n\n// Session identity. Branded so a session ID is not interchangeable with an\n// entry, part, or workspace ID at the type level — service signatures take\n// `SessionID`, never a bare `string`.\n//\n// `create` mints a new one; `ascending` adopts an ID that came from outside\n// (a persisted row, a request payload) and rejects a foreign prefix rather\n// than branding it silently. uuidv7 keeps IDs lexicographically sortable by\n// creation time, so `ORDER BY id` is `ORDER BY created`.\nexport const SessionID = Schema.String.check(Schema.isStartingWith(\"ses\")).pipe(\n\tSchema.brand(\"Session.ID\"),\n\twithStatics((schema) => ({\n\t\tascending: (id?: string) => {\n\t\t\tif (!id) return schema.make(\"ses_\" + uuidv7());\n\t\t\tif (!id.startsWith(\"ses\")) throw new Error(`ID ${id} does not start with ses`);\n\t\t\treturn schema.make(id);\n\t\t},\n\t\tcreate: () => schema.make(\"ses_\" + uuidv7()),\n\t})),\n);\nexport type SessionID = typeof SessionID.Type;\n\n/**\n * A conversation message id.\n *\n * Deliberately unprefixed. aikit mints assistant message ids itself, as bare\n * uuidv7, and `stream()` accepts no id -- so any naming rule of ours would have\n * to be imposed on messages aikit hands us, by rewriting a field of the value we\n * were given. Sharing aikit's format instead means an id means the same thing on\n * both sides of the boundary and never needs translating.\n *\n * The brand carries the meaning; uuidv7 keeps ids time-ordered, so they sort by\n * creation.\n */\nexport const MessageID = Schema.String.pipe(\n\tSchema.brand(\"Message.ID\"),\n\twithStatics((schema) => ({\n\t\tcreate: () => schema.make(uuidv7()),\n\t\t/**\n\t\t * Adopt an id minted elsewhere -- in practice aikit's, which arrives as a\n\t\t * plain string on every stream event and inside every assistant message.\n\t\t *\n\t\t * `make` does the same thing. This exists so the boundary where a foreign\n\t\t * id enters the domain is named and greppable, and so the pairing with\n\t\t * `create` says which side chose the id.\n\t\t */\n\t\tfrom: (id: string) => schema.make(id),\n\t})),\n);\nexport type MessageID = typeof MessageID.Type;\n"],"mappings":";;;;;;;;;;;;AAqBA,MAAa,YAAY,OAAO,OAAO,MAAM,OAAO,eAAe,KAAK,CAAC,CAAC,CAAC,KAC1E,OAAO,MAAM,YAAY,GACzB,aAAa,YAAY;CACxB,YAAY,OAAgB;EAC3B,IAAI,CAAC,IAAI,OAAO,OAAO,KAAK,SAAS,OAAO,CAAC;EAC7C,IAAI,CAAC,GAAG,WAAW,KAAK,GAAG,MAAM,IAAI,MAAM,MAAM,GAAG,yBAAyB;EAC7E,OAAO,OAAO,KAAK,EAAE;CACtB;CACA,cAAc,OAAO,KAAK,SAAS,OAAO,CAAC;AAC5C,EAAE,CACH;;;;;;;;;;;;;AAeA,MAAa,YAAY,OAAO,OAAO,KACtC,OAAO,MAAM,YAAY,GACzB,aAAa,YAAY;CACxB,cAAc,OAAO,KAAK,OAAO,CAAC;;;;;;;;;CASlC,OAAO,OAAe,OAAO,KAAK,EAAE;AACrC,EAAE,CACH"}
1
+ {"version":3,"file":"ids.mjs","names":[],"sources":["../../src/ids.ts"],"sourcesContent":["import { Schema } from \"effect\";\nimport { uuidv7 } from \"uuidv7\";\nimport { withStatics } from \"./schema.ts\";\n\n/**\n * The identifiers that cross the plugin boundary.\n *\n * A plugin reads a session and thread id off its context and a message id off every tool call, so both\n * brands have to be the ones the harness itself mints -- a structurally identical brand declared\n * twice is two types, and a plugin would have to cast to hand either back. They live here, in the\n * package both sides depend on, rather than being re-declared on each side.\n */\n\n// Session identity. Branded so a session ID is not interchangeable with an\n// entry, part, or workspace ID at the type level — service signatures take\n// `SessionID`, never a bare `string`.\n//\n// `create` mints a new one; `ascending` adopts an ID that came from outside\n// (a persisted row, a request payload) and rejects a foreign prefix rather\n// than branding it silently. uuidv7 keeps IDs lexicographically sortable by\n// creation time, so `ORDER BY id` is `ORDER BY created`.\nexport const SessionID = Schema.String.check(Schema.isStartingWith(\"ses\")).pipe(\n\tSchema.brand(\"Session.ID\"),\n\twithStatics((schema) => ({\n\t\tascending: (id?: string) => {\n\t\t\tif (!id) return schema.make(\"ses_\" + uuidv7());\n\t\t\tif (!id.startsWith(\"ses\")) throw new Error(`ID ${id} does not start with ses`);\n\t\t\treturn schema.make(id);\n\t\t},\n\t\tcreate: () => schema.make(\"ses_\" + uuidv7()),\n\t})),\n);\nexport type SessionID = typeof SessionID.Type;\n\n/**\n * Thread identity: one linear transcript inside a session. Every session has a `main` thread;\n * forks add more. Also the provider session and prompt-cache key, so it is fresh per thread.\n */\nexport const ThreadID = Schema.String.check(Schema.isStartingWith(\"thr\")).pipe(\n\tSchema.brand(\"Thread.ID\"),\n\twithStatics((schema) => ({\n\t\tcreate: () => schema.make(\"thr_\" + uuidv7()),\n\t})),\n);\nexport type ThreadID = typeof ThreadID.Type;\n\n/**\n * A conversation message id.\n *\n * Deliberately unprefixed. aikit mints assistant message ids itself, as bare\n * uuidv7, and `stream()` accepts no id -- so any naming rule of ours would have\n * to be imposed on messages aikit hands us, by rewriting a field of the value we\n * were given. Sharing aikit's format instead means an id means the same thing on\n * both sides of the boundary and never needs translating.\n *\n * The brand carries the meaning; uuidv7 keeps ids time-ordered, so they sort by\n * creation.\n */\nexport const MessageID = Schema.String.pipe(\n\tSchema.brand(\"Message.ID\"),\n\twithStatics((schema) => ({\n\t\tcreate: () => schema.make(uuidv7()),\n\t\t/**\n\t\t * Adopt an id minted elsewhere -- in practice aikit's, which arrives as a\n\t\t * plain string on every stream event and inside every assistant message.\n\t\t *\n\t\t * `make` does the same thing. This exists so the boundary where a foreign\n\t\t * id enters the domain is named and greppable, and so the pairing with\n\t\t * `create` says which side chose the id.\n\t\t */\n\t\tfrom: (id: string) => schema.make(id),\n\t})),\n);\nexport type MessageID = typeof MessageID.Type;\n"],"mappings":";;;;;;;;;;;;AAqBA,MAAa,YAAY,OAAO,OAAO,MAAM,OAAO,eAAe,KAAK,CAAC,CAAC,CAAC,KAC1E,OAAO,MAAM,YAAY,GACzB,aAAa,YAAY;CACxB,YAAY,OAAgB;EAC3B,IAAI,CAAC,IAAI,OAAO,OAAO,KAAK,SAAS,OAAO,CAAC;EAC7C,IAAI,CAAC,GAAG,WAAW,KAAK,GAAG,MAAM,IAAI,MAAM,MAAM,GAAG,yBAAyB;EAC7E,OAAO,OAAO,KAAK,EAAE;CACtB;CACA,cAAc,OAAO,KAAK,SAAS,OAAO,CAAC;AAC5C,EAAE,CACH;;;;;AAOA,MAAa,WAAW,OAAO,OAAO,MAAM,OAAO,eAAe,KAAK,CAAC,CAAC,CAAC,KACzE,OAAO,MAAM,WAAW,GACxB,aAAa,YAAY,EACxB,cAAc,OAAO,KAAK,SAAS,OAAO,CAAC,EAC5C,EAAE,CACH;;;;;;;;;;;;;AAeA,MAAa,YAAY,OAAO,OAAO,KACtC,OAAO,MAAM,YAAY,GACzB,aAAa,YAAY;CACxB,cAAc,OAAO,KAAK,OAAO,CAAC;;;;;;;;;CASlC,OAAO,OAAe,OAAO,KAAK,EAAE;AACrC,EAAE,CACH"}
package/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { t as section_d_exports } from "./plugin/section.mjs";
2
- import { g as tool_d_exports } from "./tool-B4nkpC9M.mjs";
3
- import { t as plugin_d_exports } from "./plugin-Cuz78r5j.mjs";
2
+ import { v as tool_d_exports } from "./tool-BRTCmPch.mjs";
3
+ import { t as plugin_d_exports } from "./plugin-BhornEkR.mjs";
4
4
  export { plugin_d_exports as Plugin, section_d_exports as Section, tool_d_exports as Tool };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codeworksh/plugin",
3
- "version": "0.3.0-canary.67.1.g251f0966",
3
+ "version": "0.3.0-canary.70.1.g64a3527d",
4
4
  "description": "SDK for building CodeWork plugins — the plugin, tool, and sandbox contracts shared with @codeworksh/harness.",
5
5
  "keywords": [
6
6
  "agent",
@@ -168,7 +168,7 @@
168
168
  "uuidv7": "^1.2.1"
169
169
  },
170
170
  "peerDependencies": {
171
- "@codeworksh/aikit": "0.12.1-canary.67.1.g251f0966",
171
+ "@codeworksh/aikit": "0.12.1-canary.70.1.g64a3527d",
172
172
  "effect": "4.0.5"
173
173
  }
174
174
  }
package/plugin/tool.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as ToolAfterResult, c as ToolBeforeResult, d as ToolRegistry, f as ToolResultContent, i as ToolAfterFn, l as ToolDefPatch, n as ToolAddOptions, o as ToolBefore, r as ToolAfter, s as ToolBeforeFn, t as HookReturn, u as ToolRegistration } from "../tool-D5487q-u.mjs";
1
+ import { a as ToolAfterResult, c as ToolBeforeResult, d as ToolRegistry, f as ToolResultContent, i as ToolAfterFn, l as ToolDefPatch, n as ToolAddOptions, o as ToolBefore, r as ToolAfter, s as ToolBeforeFn, t as HookReturn, u as ToolRegistration } from "../tool-BZXrwclV.mjs";
2
2
  export { HookReturn, ToolAddOptions, ToolAfter, ToolAfterFn, ToolAfterResult, ToolBefore, ToolBeforeFn, ToolBeforeResult, ToolDefPatch, ToolRegistration, ToolRegistry, ToolResultContent };
package/plugin/tool.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "../rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { AikitToolCallTerminalPart } from "../event.mjs";
3
- import { MessageID, SessionID } from "../ids.mjs";
3
+ import { MessageID, SessionID, ThreadID } from "../ids.mjs";
4
4
  import { ToolCallContext } from "../tool.mjs";
5
5
  import { Schema } from "effect";
6
6
  //#region src/plugin/tool.ts
@@ -12,6 +12,7 @@ var tool_exports = /* @__PURE__ */ __exportAll({
12
12
  const ToolBefore = Schema.Struct({
13
13
  ...ToolCallContext.fields,
14
14
  sessionId: SessionID,
15
+ threadId: ThreadID,
15
16
  messageId: MessageID,
16
17
  params: Schema.Unknown
17
18
  });
@@ -1 +1 @@
1
- {"version":3,"file":"tool.mjs","names":[],"sources":["../../../src/plugin/tool.ts"],"sourcesContent":["import { type Effect, Schema } from \"effect\";\nimport { AikitToolCallTerminalPart } from \"../event.ts\";\nimport { MessageID, SessionID } from \"../ids.ts\";\nimport { type AnyToolDef, type ModelContent, type RegisteredTool, ToolCallContext } from \"../tool.ts\";\n\nexport const ToolBefore = Schema.Struct({\n\t...ToolCallContext.fields,\n\tsessionId: SessionID,\n\tmessageId: MessageID,\n\tparams: Schema.Unknown,\n});\nexport type ToolBefore = typeof ToolBefore.Type;\nexport const ToolAfter = Schema.Struct({ ...ToolBefore.fields, terminal: AikitToolCallTerminalPart });\nexport type ToolAfter = typeof ToolAfter.Type;\nexport const ToolBeforeResult = Schema.Struct({ block: Schema.Boolean, reason: Schema.optional(Schema.String) });\nexport type ToolBeforeResult = typeof ToolBeforeResult.Type;\nexport type ToolResultContent = ModelContent;\nexport interface ToolAfterResult {\n\treadonly content?: ToolResultContent;\n\treadonly details?: unknown;\n\treadonly isError?: boolean;\n}\nexport type HookReturn<A> = A | void | Promise<A | void> | Effect.Effect<A | void, unknown>;\nexport type ToolBeforeFn = (call: ToolBefore) => HookReturn<ToolBeforeResult>;\nexport type ToolAfterFn = (call: ToolAfter) => HookReturn<ToolAfterResult>;\nexport interface ToolAddOptions {\n\treadonly beforeToolCall?: ToolBeforeFn;\n\treadonly afterToolCall?: ToolAfterFn;\n}\nexport interface ToolDefPatch {\n\treadonly description?: string;\n\treadonly label?: string;\n\treadonly promptSnippet?: string;\n\treadonly promptGuidelines?: ReadonlyArray<string>;\n}\n/**\n * One frozen bucket entry: the winning tool for a name together with the hooks that\n * `add` declared alongside it. Kept here rather than in the bucket implementation so\n * the executor shares the contract without importing plugin assembly.\n */\nexport interface ToolRegistration {\n\treadonly tool: RegisteredTool;\n\treadonly hooks: ToolAddOptions;\n}\nexport interface ToolRegistry {\n\treadonly add: (tool: RegisteredTool, options?: ToolAddOptions) => void;\n\treadonly update: (name: string, patch: ToolDefPatch) => void;\n\treadonly list: () => ReadonlyArray<AnyToolDef>;\n\treadonly get: (name: string) => AnyToolDef | undefined;\n\treadonly has: (name: string) => boolean;\n}\n"],"mappings":";;;;;;;;;;;AAKA,MAAa,aAAa,OAAO,OAAO;CACvC,GAAG,gBAAgB;CACnB,WAAW;CACX,WAAW;CACX,QAAQ,OAAO;AAChB,CAAC;AAED,MAAa,YAAY,OAAO,OAAO;CAAE,GAAG,WAAW;CAAQ,UAAU;AAA0B,CAAC;AAEpG,MAAa,mBAAmB,OAAO,OAAO;CAAE,OAAO,OAAO;CAAS,QAAQ,OAAO,SAAS,OAAO,MAAM;AAAE,CAAC"}
1
+ {"version":3,"file":"tool.mjs","names":[],"sources":["../../../src/plugin/tool.ts"],"sourcesContent":["import { type Effect, Schema } from \"effect\";\nimport { AikitToolCallTerminalPart } from \"../event.ts\";\nimport { MessageID, SessionID, ThreadID } from \"../ids.ts\";\nimport { type AnyToolDef, type ModelContent, type RegisteredTool, ToolCallContext } from \"../tool.ts\";\n\nexport const ToolBefore = Schema.Struct({\n\t...ToolCallContext.fields,\n\tsessionId: SessionID,\n\tthreadId: ThreadID,\n\tmessageId: MessageID,\n\tparams: Schema.Unknown,\n});\nexport type ToolBefore = typeof ToolBefore.Type;\nexport const ToolAfter = Schema.Struct({ ...ToolBefore.fields, terminal: AikitToolCallTerminalPart });\nexport type ToolAfter = typeof ToolAfter.Type;\nexport const ToolBeforeResult = Schema.Struct({ block: Schema.Boolean, reason: Schema.optional(Schema.String) });\nexport type ToolBeforeResult = typeof ToolBeforeResult.Type;\nexport type ToolResultContent = ModelContent;\nexport interface ToolAfterResult {\n\treadonly content?: ToolResultContent;\n\treadonly details?: unknown;\n\treadonly isError?: boolean;\n}\nexport type HookReturn<A> = A | void | Promise<A | void> | Effect.Effect<A | void, unknown>;\nexport type ToolBeforeFn = (call: ToolBefore) => HookReturn<ToolBeforeResult>;\nexport type ToolAfterFn = (call: ToolAfter) => HookReturn<ToolAfterResult>;\nexport interface ToolAddOptions {\n\treadonly beforeToolCall?: ToolBeforeFn;\n\treadonly afterToolCall?: ToolAfterFn;\n}\nexport interface ToolDefPatch {\n\treadonly description?: string;\n\treadonly label?: string;\n\treadonly promptSnippet?: string;\n\treadonly promptGuidelines?: ReadonlyArray<string>;\n}\n/**\n * One frozen bucket entry: the winning tool for a name together with the hooks that\n * `add` declared alongside it. Kept here rather than in the bucket implementation so\n * the executor shares the contract without importing plugin assembly.\n */\nexport interface ToolRegistration {\n\treadonly tool: RegisteredTool;\n\treadonly hooks: ToolAddOptions;\n}\nexport interface ToolRegistry {\n\treadonly add: (tool: RegisteredTool, options?: ToolAddOptions) => void;\n\treadonly update: (name: string, patch: ToolDefPatch) => void;\n\treadonly list: () => ReadonlyArray<AnyToolDef>;\n\treadonly get: (name: string) => AnyToolDef | undefined;\n\treadonly has: (name: string) => boolean;\n}\n"],"mappings":";;;;;;;;;;;AAKA,MAAa,aAAa,OAAO,OAAO;CACvC,GAAG,gBAAgB;CACnB,WAAW;CACX,UAAU;CACV,WAAW;CACX,QAAQ,OAAO;AAChB,CAAC;AAED,MAAa,YAAY,OAAO,OAAO;CAAE,GAAG,WAAW;CAAQ,UAAU;AAA0B,CAAC;AAEpG,MAAa,mBAAmB,OAAO,OAAO;CAAE,OAAO,OAAO;CAAS,QAAQ,OAAO,SAAS,OAAO,MAAM;AAAE,CAAC"}
@@ -1,11 +1,11 @@
1
1
  import { i as Definition, o as Payload, r as Data, s as PublishOptions } from "./event-C6-oCzlq.mjs";
2
- import { n as SessionID } from "./ids-CHjmAdTc.mjs";
2
+ import { n as SessionID, r as ThreadID } from "./ids-CpPeP5Ks.mjs";
3
3
  import { o as Service, r as Info } from "./location-Q39els63.mjs";
4
4
  import { f as io_d_exports, i as Identity, s as Provides } from "./io-Br9WZTsG.mjs";
5
5
  import { i as Info$1 } from "./settings-DGYWREuu.mjs";
6
6
  import { t as section_d_exports } from "./plugin/section.mjs";
7
7
  import { n as prompt_d_exports, t as PromptRegistry } from "./prompt-DWaA5ZXj.mjs";
8
- import { d as ToolRegistry, p as tool_d_exports } from "./tool-D5487q-u.mjs";
8
+ import { d as ToolRegistry, p as tool_d_exports } from "./tool-BZXrwclV.mjs";
9
9
  import { Model } from "@codeworksh/aikit";
10
10
  import { Effect } from "effect";
11
11
  //#region src/plugin/registry.d.ts
@@ -51,6 +51,8 @@ interface Paths {
51
51
  /** One object, shared by every plugin in one turn. */
52
52
  interface SharedPluginContext {
53
53
  readonly sessionId: SessionID;
54
+ /** The thread whose turn this is. `sandbox` and `location` are its placement, else the session's. */
55
+ readonly threadId: ThreadID;
54
56
  readonly sandbox: Identity;
55
57
  readonly paths: Paths;
56
58
  readonly location: Info;
@@ -155,4 +157,4 @@ declare namespace plugin_d_exports {
155
157
  }
156
158
  //#endregion
157
159
  export { PluginRegistry as _, define as a, PluginOptions as c, PluginSpec as d, Config as f, SharedPluginContext as g, PromptResolver as h, PluginKind as i, PluginPatch as l, Paths as m, Mount as n, domains as o, Events as p, Plugin as r, rank as s, plugin_d_exports as t, PluginRef as u };
158
- //# sourceMappingURL=plugin-Cuz78r5j.d.mts.map
160
+ //# sourceMappingURL=plugin-BhornEkR.d.mts.map
package/plugin.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as section_d_exports } from "./plugin/section.mjs";
2
2
  import { n as prompt_d_exports } from "./prompt-DWaA5ZXj.mjs";
3
- import { p as tool_d_exports } from "./tool-D5487q-u.mjs";
4
- import { _ as PluginRegistry, a as define, c as PluginOptions, d as PluginSpec, f as Config, g as SharedPluginContext, h as PromptResolver, i as PluginKind, l as PluginPatch, m as Paths, n as Mount, o as domains, p as Events, r as Plugin, s as rank, u as PluginRef } from "./plugin-Cuz78r5j.mjs";
3
+ import { p as tool_d_exports } from "./tool-BZXrwclV.mjs";
4
+ import { _ as PluginRegistry, a as define, c as PluginOptions, d as PluginSpec, f as Config, g as SharedPluginContext, h as PromptResolver, i as PluginKind, l as PluginPatch, m as Paths, n as Mount, o as domains, p as Events, r as Plugin, s as rank, u as PluginRef } from "./plugin-BhornEkR.mjs";
5
5
  export { type Config, type Events, type Mount, type Paths, type Plugin, type PluginKind, type PluginOptions, type PluginPatch, type PluginRef, type PluginRegistry, type PluginSpec, prompt_d_exports as Prompt, type PromptResolver, section_d_exports as Section, type SharedPluginContext, tool_d_exports as Tool, define, domains, rank };
@@ -1,2 +1,2 @@
1
- import { _ as IToolProgress, b as make, v as ToolProgress, x as noop, y as ToolProgressPartial } from "../tool-B4nkpC9M.mjs";
1
+ import { C as noop, S as make, b as ToolProgress, x as ToolProgressPartial, y as IToolProgress } from "../tool-BRTCmPch.mjs";
2
2
  export { IToolProgress, ToolProgress, ToolProgressPartial, make, noop };
@@ -26,7 +26,7 @@ declare const make$1: (report: IToolProgress["report"]) => Layer.Layer<ToolProgr
26
26
  /** Drops every update — the default until the executor wires a live event sink. */
27
27
  declare const noop: Layer.Layer<ToolProgress>;
28
28
  declare namespace tool_d_exports {
29
- export { AnyToolDef, AnyToolImpl, Handler, ModelContent, RegisteredTool, ToolCallContext, ToolDef, ToolImpl, define, implement, make, provide, register, toAikitTool, toProviderJsonSchema };
29
+ export { AnyToolDef, AnyToolImpl, Handler, ModelContent, RegisteredTool, ToolCallContext, ToolDef, ToolExposure, ToolImpl, declared, define, implement, make, provide, register, toAikitTool, toProviderJsonSchema };
30
30
  }
31
31
  /**
32
32
  * The tool definition + handler model.
@@ -54,6 +54,17 @@ declare const ToolCallContext: Schema.Struct<{
54
54
  readonly modelInput: Schema.optional<Schema.$Array<Schema.Literals<readonly ["text", "image"]>>>;
55
55
  }>;
56
56
  type ToolCallContext = typeof ToolCallContext.Type;
57
+ /**
58
+ * Where a tool is reachable. `direct` and `model` tools are declared to the model each turn;
59
+ * `model` ones are never callable from other tools. `codemode` and `deferred` tools stay off the
60
+ * wire until loaded, and `hidden` ones never reach the model.
61
+ */
62
+ declare const ToolExposure: Schema.Literals<readonly ["direct", "model", "codemode", "deferred", "hidden"]>;
63
+ type ToolExposure = typeof ToolExposure.Type;
64
+ /** Whether a tool is declared to the model every turn. Omitted exposure means `direct`. */
65
+ declare const declared: (def: {
66
+ readonly exposure?: ToolExposure;
67
+ }) => boolean;
57
68
  /**
58
69
  * A pure tool definition. Parametrised over the *schema* instances so the
59
70
  * decoded parameter/success/failure types can be recovered via `["Type"]`.
@@ -70,6 +81,8 @@ interface ToolDef<Name extends string = string, Params extends Schema.Top = Sche
70
81
  readonly promptSnippet?: string;
71
82
  /** Optional guideline bullets appended to the default system prompt Guidelines section when this tool is active. */
72
83
  readonly promptGuidelines?: ReadonlyArray<string>;
84
+ /** Where the tool is reachable. Omit → `direct`. */
85
+ readonly exposure?: ToolExposure;
73
86
  /**
74
87
  * Repair argument shapes models commonly send before they are validated against
75
88
  * `parameters`. Return a copy; a throw makes the arguments invalid.
@@ -109,6 +122,7 @@ interface DefineInput<Name extends string, Params extends Schema.Top, Success ex
109
122
  readonly label?: string;
110
123
  readonly promptSnippet?: string;
111
124
  readonly promptGuidelines?: ReadonlyArray<string>;
125
+ readonly exposure?: ToolExposure;
112
126
  readonly prepareArguments?: (args: unknown) => unknown;
113
127
  readonly parameters: Params;
114
128
  readonly constrainedSampling?: Message.Tool["constrainedSampling"];
@@ -159,5 +173,5 @@ declare const toProviderJsonSchema: (schema: Schema.Top) => Record<string, unkno
159
173
  */
160
174
  declare const toAikitTool: (def: AnyToolDef) => Message.Tool;
161
175
  //#endregion
162
- export { IToolProgress as _, RegisteredTool as a, make$1 as b, ToolImpl as c, make as d, provide as f, tool_d_exports as g, toProviderJsonSchema as h, ModelContent as i, define as l, toAikitTool as m, AnyToolImpl as n, ToolCallContext as o, register as p, Handler as r, ToolDef as s, AnyToolDef as t, implement as u, ToolProgress as v, noop as x, ToolProgressPartial as y };
163
- //# sourceMappingURL=tool-B4nkpC9M.d.mts.map
176
+ export { noop as C, make$1 as S, toProviderJsonSchema as _, RegisteredTool as a, ToolProgress as b, ToolExposure as c, define as d, implement as f, toAikitTool as g, register as h, ModelContent as i, ToolImpl as l, provide as m, AnyToolImpl as n, ToolCallContext as o, make as p, Handler as r, ToolDef as s, AnyToolDef as t, declared as u, tool_d_exports as v, ToolProgressPartial as x, IToolProgress as y };
177
+ //# sourceMappingURL=tool-BRTCmPch.d.mts.map
@@ -1,4 +1,4 @@
1
- import { a as RegisteredTool, i as ModelContent, t as AnyToolDef } from "./tool-B4nkpC9M.mjs";
1
+ import { a as RegisteredTool, i as ModelContent, t as AnyToolDef } from "./tool-BRTCmPch.mjs";
2
2
  import { Effect, Schema } from "effect";
3
3
  declare namespace tool_d_exports {
4
4
  export { HookReturn, ToolAddOptions, ToolAfter, ToolAfterFn, ToolAfterResult, ToolBefore, ToolBeforeFn, ToolBeforeResult, ToolDefPatch, ToolRegistration, ToolRegistry, ToolResultContent };
@@ -12,6 +12,9 @@ declare const ToolBefore: Schema.Struct<{
12
12
  ascending: (id?: string) => string & import("effect/Brand").Brand<"Session.ID">;
13
13
  create: () => string & import("effect/Brand").Brand<"Session.ID">;
14
14
  };
15
+ readonly threadId: Schema.brand<Schema.String, "Thread.ID"> & {
16
+ create: () => string & import("effect/Brand").Brand<"Thread.ID">;
17
+ };
15
18
  readonly messageId: Schema.brand<Schema.String, "Message.ID"> & {
16
19
  create: () => string & import("effect/Brand").Brand<"Message.ID">;
17
20
  from: (id: string) => string & import("effect/Brand").Brand<"Message.ID">;
@@ -28,6 +31,9 @@ declare const ToolAfter: Schema.Struct<{
28
31
  ascending: (id?: string) => string & import("effect/Brand").Brand<"Session.ID">;
29
32
  create: () => string & import("effect/Brand").Brand<"Session.ID">;
30
33
  };
34
+ readonly threadId: Schema.brand<Schema.String, "Thread.ID"> & {
35
+ create: () => string & import("effect/Brand").Brand<"Thread.ID">;
36
+ };
31
37
  readonly messageId: Schema.brand<Schema.String, "Message.ID"> & {
32
38
  create: () => string & import("effect/Brand").Brand<"Message.ID">;
33
39
  from: (id: string) => string & import("effect/Brand").Brand<"Message.ID">;
@@ -278,4 +284,4 @@ interface ToolRegistry {
278
284
  }
279
285
  //#endregion
280
286
  export { ToolAfterResult as a, ToolBeforeResult as c, ToolRegistry as d, ToolResultContent as f, ToolAfterFn as i, ToolDefPatch as l, ToolAddOptions as n, ToolBefore as o, tool_d_exports as p, ToolAfter as r, ToolBeforeFn as s, HookReturn as t, ToolRegistration as u };
281
- //# sourceMappingURL=tool-D5487q-u.d.mts.map
287
+ //# sourceMappingURL=tool-BZXrwclV.d.mts.map
package/tool.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as RegisteredTool, c as ToolImpl, d as make, f as provide, h as toProviderJsonSchema, i as ModelContent, l as define, m as toAikitTool, n as AnyToolImpl, o as ToolCallContext, p as register, r as Handler, s as ToolDef, t as AnyToolDef, u as implement } from "./tool-B4nkpC9M.mjs";
2
- export { AnyToolDef, AnyToolImpl, Handler, ModelContent, RegisteredTool, ToolCallContext, ToolDef, ToolImpl, define, implement, make, provide, register, toAikitTool, toProviderJsonSchema };
1
+ import { _ as toProviderJsonSchema, a as RegisteredTool, c as ToolExposure, d as define, f as implement, g as toAikitTool, h as register, i as ModelContent, l as ToolImpl, m as provide, n as AnyToolImpl, o as ToolCallContext, p as make, r as Handler, s as ToolDef, t as AnyToolDef, u as declared } from "./tool-BRTCmPch.mjs";
2
+ export { AnyToolDef, AnyToolImpl, Handler, ModelContent, RegisteredTool, ToolCallContext, ToolDef, ToolExposure, ToolImpl, declared, define, implement, make, provide, register, toAikitTool, toProviderJsonSchema };
package/tool.mjs CHANGED
@@ -4,6 +4,8 @@ import { Effect, Schema, SchemaAST } from "effect";
4
4
  //#region src/tool.ts
5
5
  var tool_exports = /* @__PURE__ */ __exportAll({
6
6
  ToolCallContext: () => ToolCallContext,
7
+ ToolExposure: () => ToolExposure,
8
+ declared: () => declared,
7
9
  define: () => define,
8
10
  implement: () => implement,
9
11
  make: () => make,
@@ -20,6 +22,20 @@ const ToolCallContext = Schema.Struct({
20
22
  /** Input modalities of the model the call answers, e.g. `["text", "image"]`. */
21
23
  modelInput: Schema.optional(Schema.Array(Schema.Literals(["text", "image"])))
22
24
  });
25
+ /**
26
+ * Where a tool is reachable. `direct` and `model` tools are declared to the model each turn;
27
+ * `model` ones are never callable from other tools. `codemode` and `deferred` tools stay off the
28
+ * wire until loaded, and `hidden` ones never reach the model.
29
+ */
30
+ const ToolExposure = Schema.Literals([
31
+ "direct",
32
+ "model",
33
+ "codemode",
34
+ "deferred",
35
+ "hidden"
36
+ ]);
37
+ /** Whether a tool is declared to the model every turn. Omitted exposure means `direct`. */
38
+ const declared = (def) => def.exposure === void 0 || def.exposure === "direct" || def.exposure === "model";
23
39
  /** Define a pure tool (handler attached later via {@link implement} or a toolkit). */
24
40
  const define = (input) => ({ ...input });
25
41
  /** Attach a handler to an existing definition (the testable def/exec split). */
@@ -77,6 +93,6 @@ const toAikitTool = (def) => ({
77
93
  ...def.constrainedSampling === void 0 ? {} : { constrainedSampling: def.constrainedSampling }
78
94
  });
79
95
  //#endregion
80
- export { ToolCallContext, define, implement, make, provide, register, tool_exports as t, toAikitTool, toProviderJsonSchema };
96
+ export { ToolCallContext, ToolExposure, declared, define, implement, make, provide, register, tool_exports as t, toAikitTool, toProviderJsonSchema };
81
97
 
82
98
  //# sourceMappingURL=tool.mjs.map
package/tool.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tool.mjs","names":[],"sources":["../../src/tool.ts"],"sourcesContent":["import type { Message } from \"@codeworksh/aikit\";\nimport { Effect, type Layer, Schema, SchemaAST } from \"effect\";\nimport type { TSchema } from \"typebox\";\nimport { ToolExecutionError } from \"./tool/error.ts\";\nimport type { ToolProgress } from \"./tool/progress.ts\";\n\n/**\n * The tool definition + handler model.\n *\n * A tool definition is pure, serializable data: name, description, and Effect\n * Schema for parameters / success / failure. Execution is a separate `Handler`\n * — an `Effect` whose capability dependencies (e.g. `ToolShell`) live in its\n * requirements `R`, provided by a Layer at runtime. Separating the two is the\n * main testing win: assert on the definition as plain data, and run the handler\n * against a stub capability Layer.\n *\n * Effect Schema is the single source of truth. {@link toAikitTool} derives a\n * provider-safe JSON Schema object for the aikit wire view; the harness\n * decode/encodes arguments and results with Effect Schema natively (it does not\n * use aikit's Typebox validators).\n */\n\n/** What the model reads next turn (the `content` side of content/details). */\nexport type ModelContent = ReadonlyArray<Message.TextContent | Message.ImageContent>;\n\n/** Per-call metadata handed to a handler instead of positional args. */\nexport const ToolCallContext = Schema.Struct({\n\tcallID: Schema.String,\n\ttoolName: Schema.String,\n\trawArgs: Schema.Record(Schema.String, Schema.Unknown),\n\t/** Input modalities of the model the call answers, e.g. `[\"text\", \"image\"]`. */\n\tmodelInput: Schema.optional(Schema.Array(Schema.Literals([\"text\", \"image\"]))),\n});\nexport type ToolCallContext = typeof ToolCallContext.Type;\n\n/**\n * A pure tool definition. Parametrised over the *schema* instances so the\n * decoded parameter/success/failure types can be recovered via `[\"Type\"]`.\n */\nexport interface ToolDef<\n\tName extends string = string,\n\tParams extends Schema.Top = Schema.Top,\n\tSuccess extends Schema.Top = Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n> {\n\treadonly name: Name;\n\treadonly description: string;\n\t/** Human-readable display label (kept from the previous `AgentTool`). */\n\treadonly label?: string;\n\t/**\n\t * A short one-line summary for compact tool listings (e.g. a system-prompt tool index),\n\t * distinct from the fuller `description`.\n\t */\n\treadonly promptSnippet?: string;\n\t/** Optional guideline bullets appended to the default system prompt Guidelines section when this tool is active. */\n\treadonly promptGuidelines?: ReadonlyArray<string>;\n\t/**\n\t * Repair argument shapes models commonly send before they are validated against\n\t * `parameters`. Return a copy; a throw makes the arguments invalid.\n\t */\n\treadonly prepareArguments?: (args: unknown) => unknown;\n\treadonly parameters: Params;\n\t/**\n\t * How the provider constrains the generated arguments. `{ type: \"json_schema\", strict: \"prefer\" }` sends\n\t * `parameters` in strict mode where the provider can express it and falls back to non-strict otherwise.\n\t */\n\treadonly constrainedSampling?: Message.Tool[\"constrainedSampling\"];\n\treadonly success: Success;\n\t/** Declared, model-visible failures (typed). Omit for tools that cannot fail expectedly. */\n\treadonly failure?: Failure;\n\t/** Render success for the model. Omit → executor falls back to JSON text. */\n\treadonly encodeContent?: (success: Success[\"Type\"]) => ModelContent;\n\t/** Render an expected failure for the model. Omit → executor falls back to JSON text. */\n\treadonly encodeFailureContent?: (failure: Failure[\"Type\"]) => ModelContent;\n\t/**\n\t * The `details` kept with a success, for UIs and programmatic consumers. Omit → the encoded\n\t * success. Set it when `encodeContent` already carries the payload, so it is not stored twice.\n\t */\n\treadonly encodeDetails?: (success: Success[\"Type\"]) => unknown;\n}\n\n/** A handler: validated params + context → typed success or typed failure. */\nexport type Handler<Params extends Schema.Top, Success extends Schema.Top, Failure extends Schema.Top, R = never> = (\n\tparams: Params[\"Type\"],\n\tctx: ToolCallContext,\n) => Effect.Effect<Success[\"Type\"], Failure[\"Type\"], R>;\n\n/** A definition paired with its handler (the unit the executor runs). */\nexport interface ToolImpl<\n\tName extends string = string,\n\tParams extends Schema.Top = Schema.Top,\n\tSuccess extends Schema.Top = Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n\tR = never,\n> {\n\treadonly definition: ToolDef<Name, Params, Success, Failure>;\n\treadonly handler: Handler<Params, Success, Failure, R>;\n}\n\n// Heterogeneous-collection aliases. `any` for the schema generics keeps handlers\n// of differing parameter types assignable into one array (the precise generics\n// live on the authoring helpers below).\n// biome-ignore lint/suspicious/noExplicitAny: erased schema generics for storage\nexport type AnyToolDef = ToolDef<string, any, any, any>;\n// biome-ignore lint/suspicious/noExplicitAny: erased schema generics for storage\nexport type AnyToolImpl<R = never> = ToolImpl<string, any, any, any, R>;\n\ninterface DefineInput<\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n> {\n\treadonly name: Name;\n\treadonly description: string;\n\treadonly label?: string;\n\treadonly promptSnippet?: string;\n\treadonly promptGuidelines?: ReadonlyArray<string>;\n\treadonly prepareArguments?: (args: unknown) => unknown;\n\treadonly parameters: Params;\n\treadonly constrainedSampling?: Message.Tool[\"constrainedSampling\"];\n\treadonly success: Success;\n\treadonly failure?: Failure;\n\treadonly encodeContent?: (success: Success[\"Type\"]) => ModelContent;\n\treadonly encodeFailureContent?: (failure: Failure[\"Type\"]) => ModelContent;\n\treadonly encodeDetails?: (success: Success[\"Type\"]) => unknown;\n}\n\n/** Define a pure tool (handler attached later via {@link implement} or a toolkit). */\nexport const define = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n>(\n\tinput: DefineInput<Name, Params, Success, Failure>,\n): ToolDef<Name, Params, Success, Failure> => ({\n\t...input,\n});\n\n/** Attach a handler to an existing definition (the testable def/exec split). */\nexport const implement = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n\tR = never,\n>(\n\tdefinition: ToolDef<Name, Params, Success, Failure>,\n\thandler: Handler<Params, Success, Failure, R>,\n): ToolImpl<Name, Params, Success, Failure, R> => ({ definition, handler });\n\n/** Sugar for the co-located case: a definition with its handler in one object. */\nexport const make = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n\tR = never,\n>(\n\tinput: DefineInput<Name, Params, Success, Failure> & {\n\t\treadonly handler: Handler<Params, Success, Failure, R>;\n\t},\n): ToolImpl<Name, Params, Success, Failure, R> => {\n\tconst { handler, ...rest } = input;\n\treturn { definition: define(rest), handler };\n};\n\n/**\n * A tool ready to register: its capability requirements have been discharged, leaving only\n * the executor-provided {@link ToolProgress}. The registry and executor hold `RegisteredTool`s\n * and are non-generic (only `handle` is generic, over a progress sink's `RProgress`), so any\n * number of tools — built-in or\n * third-party/plugin — compose without a shared capability union\n */\nexport interface RegisteredTool {\n\treadonly definition: AnyToolDef;\n\treadonly handler: (\n\t\tparams: unknown,\n\t\tctx: ToolCallContext,\n\t) => Effect.Effect<unknown, ToolExecutionError, ToolProgress>;\n}\n\nconst toRegistered = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n>(\n\tdefinition: ToolDef<Name, Params, Success, Failure>,\n\thandler: Handler<Params, Success, Failure, ToolProgress>,\n): RegisteredTool => ({\n\tdefinition,\n\t// The executor decodes with `definition.parameters` before invoking this\n\t// erased handler, so restoring the authored parameter type is safe here.\n\thandler: (params, ctx) =>\n\t\thandler(params as Params[\"Type\"], ctx).pipe(\n\t\t\tEffect.mapError((cause) => new ToolExecutionError({ toolName: definition.name, cause })),\n\t\t),\n});\n\n/** Register a tool whose only requirement is the executor-provided progress service. */\nexport const register = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n>(\n\timpl: ToolImpl<Name, Params, Success, Failure, ToolProgress>,\n): RegisteredTool => toRegistered(impl.definition, impl.handler);\n\n/**\n * Discharge a tool's capability requirements into a {@link RegisteredTool}, erasing its `R`\n * (the executor still provides `ToolProgress`). This is the registration boundary: a\n * plugin/third-party tool provides its own fully-resolved capability Layer here, so the\n * registry never has to unify anyone's `R`.\n */\nexport const provide = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n\tR,\n>(\n\timpl: ToolImpl<Name, Params, Success, Failure, R | ToolProgress>,\n\tlayer: Layer.Layer<R>,\n): RegisteredTool =>\n\t// `Effect.provide` discharges `R`, leaving `ToolProgress`. TS can't simplify\n\t// `Exclude<ToolProgress, R>` for a generic `R`, so localize the cast before\n\t// crossing the registered-tool boundary.\n\ttoRegistered(impl.definition, ((params, ctx) => impl.handler(params, ctx).pipe(Effect.provide(layer))) as Handler<\n\t\tParams,\n\t\tSuccess,\n\t\tFailure,\n\t\tToolProgress\n\t>);\n\n/**\n * Derive a provider-safe JSON Schema object from an Effect Schema. This is the\n * single boundary that crosses into the provider wire; if a provider rejects a\n * construct, fix it here. Draft-07 inlines the root (no top-level `$ref`).\n */\nexport const toProviderJsonSchema = (schema: Schema.Top): Record<string, unknown> => {\n\t// Effect reads `Struct({})` as TS `{}` (any non-null) and emits `{ not: { type: \"null\" } }`;\n\t// providers require an object, so emit one shaped like a non-empty struct's.\n\tconst encoded = SchemaAST.toEncoded(schema.ast);\n\tif (\n\t\tSchemaAST.isObjects(encoded) &&\n\t\tencoded.propertySignatures.length === 0 &&\n\t\tencoded.indexSignatures.length === 0\n\t) {\n\t\treturn { type: \"object\", properties: {}, additionalProperties: true };\n\t}\n\treturn Schema.toStandardJSONSchemaV1(schema)[\"~standard\"].jsonSchema.input({ target: \"draft-07\" });\n};\n\n/**\n * Build the aikit `Message.Tool` wire view from a definition. The derived JSON\n * Schema object satisfies aikit's `parameters` slot structurally at runtime; the\n * single localized cast keeps aikit untouched (decision 3-A).\n */\nexport const toAikitTool = (def: AnyToolDef): Message.Tool => ({\n\tname: def.name,\n\tdescription: def.description,\n\tparameters: toProviderJsonSchema(def.parameters) as unknown as TSchema,\n\t...(def.constrainedSampling === undefined ? {} : { constrainedSampling: def.constrainedSampling }),\n});\n"],"mappings":";;;;;;;;;;;;;;;AA0BA,MAAa,kBAAkB,OAAO,OAAO;CAC5C,QAAQ,OAAO;CACf,UAAU,OAAO;CACjB,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO;;CAEpD,YAAY,OAAO,SAAS,OAAO,MAAM,OAAO,SAAS,CAAC,QAAQ,OAAO,CAAC,CAAC,CAAC;AAC7E,CAAC;;AAiGD,MAAa,UAMZ,WAC8C,EAC9C,GAAG,MACJ;;AAGA,MAAa,aAOZ,YACA,aACkD;CAAE;CAAY;AAAQ;;AAGzE,MAAa,QAOZ,UAGiD;CACjD,MAAM,EAAE,SAAS,GAAG,SAAS;CAC7B,OAAO;EAAE,YAAY,OAAO,IAAI;EAAG;CAAQ;AAC5C;AAiBA,MAAM,gBAML,YACA,aACqB;CACrB;CAGA,UAAU,QAAQ,QACjB,QAAQ,QAA0B,GAAG,CAAC,CAAC,KACtC,OAAO,UAAU,UAAU,IAAI,mBAAmB;EAAE,UAAU,WAAW;EAAM;CAAM,CAAC,CAAC,CACxF;AACF;;AAGA,MAAa,YAMZ,SACoB,aAAa,KAAK,YAAY,KAAK,OAAO;;;;;;;AAQ/D,MAAa,WAOZ,MACA,UAKA,aAAa,KAAK,cAAc,QAAQ,QAAQ,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK,OAAO,QAAQ,KAAK,CAAC,EAKnG;;;;;;AAOF,MAAa,wBAAwB,WAAgD;CAGpF,MAAM,UAAU,UAAU,UAAU,OAAO,GAAG;CAC9C,IACC,UAAU,UAAU,OAAO,KAC3B,QAAQ,mBAAmB,WAAW,KACtC,QAAQ,gBAAgB,WAAW,GAEnC,OAAO;EAAE,MAAM;EAAU,YAAY,CAAC;EAAG,sBAAsB;CAAK;CAErE,OAAO,OAAO,uBAAuB,MAAM,CAAC,CAAC,YAAY,CAAC,WAAW,MAAM,EAAE,QAAQ,WAAW,CAAC;AAClG;;;;;;AAOA,MAAa,eAAe,SAAmC;CAC9D,MAAM,IAAI;CACV,aAAa,IAAI;CACjB,YAAY,qBAAqB,IAAI,UAAU;CAC/C,GAAI,IAAI,wBAAwB,KAAA,IAAY,CAAC,IAAI,EAAE,qBAAqB,IAAI,oBAAoB;AACjG"}
1
+ {"version":3,"file":"tool.mjs","names":[],"sources":["../../src/tool.ts"],"sourcesContent":["import type { Message } from \"@codeworksh/aikit\";\nimport { Effect, type Layer, Schema, SchemaAST } from \"effect\";\nimport type { TSchema } from \"typebox\";\nimport { ToolExecutionError } from \"./tool/error.ts\";\nimport type { ToolProgress } from \"./tool/progress.ts\";\n\n/**\n * The tool definition + handler model.\n *\n * A tool definition is pure, serializable data: name, description, and Effect\n * Schema for parameters / success / failure. Execution is a separate `Handler`\n * — an `Effect` whose capability dependencies (e.g. `ToolShell`) live in its\n * requirements `R`, provided by a Layer at runtime. Separating the two is the\n * main testing win: assert on the definition as plain data, and run the handler\n * against a stub capability Layer.\n *\n * Effect Schema is the single source of truth. {@link toAikitTool} derives a\n * provider-safe JSON Schema object for the aikit wire view; the harness\n * decode/encodes arguments and results with Effect Schema natively (it does not\n * use aikit's Typebox validators).\n */\n\n/** What the model reads next turn (the `content` side of content/details). */\nexport type ModelContent = ReadonlyArray<Message.TextContent | Message.ImageContent>;\n\n/** Per-call metadata handed to a handler instead of positional args. */\nexport const ToolCallContext = Schema.Struct({\n\tcallID: Schema.String,\n\ttoolName: Schema.String,\n\trawArgs: Schema.Record(Schema.String, Schema.Unknown),\n\t/** Input modalities of the model the call answers, e.g. `[\"text\", \"image\"]`. */\n\tmodelInput: Schema.optional(Schema.Array(Schema.Literals([\"text\", \"image\"]))),\n});\nexport type ToolCallContext = typeof ToolCallContext.Type;\n\n/**\n * Where a tool is reachable. `direct` and `model` tools are declared to the model each turn;\n * `model` ones are never callable from other tools. `codemode` and `deferred` tools stay off the\n * wire until loaded, and `hidden` ones never reach the model.\n */\nexport const ToolExposure = Schema.Literals([\"direct\", \"model\", \"codemode\", \"deferred\", \"hidden\"]);\nexport type ToolExposure = typeof ToolExposure.Type;\n\n/** Whether a tool is declared to the model every turn. Omitted exposure means `direct`. */\nexport const declared = (def: { readonly exposure?: ToolExposure }): boolean =>\n\tdef.exposure === undefined || def.exposure === \"direct\" || def.exposure === \"model\";\n\n/**\n * A pure tool definition. Parametrised over the *schema* instances so the\n * decoded parameter/success/failure types can be recovered via `[\"Type\"]`.\n */\nexport interface ToolDef<\n\tName extends string = string,\n\tParams extends Schema.Top = Schema.Top,\n\tSuccess extends Schema.Top = Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n> {\n\treadonly name: Name;\n\treadonly description: string;\n\t/** Human-readable display label (kept from the previous `AgentTool`). */\n\treadonly label?: string;\n\t/**\n\t * A short one-line summary for compact tool listings (e.g. a system-prompt tool index),\n\t * distinct from the fuller `description`.\n\t */\n\treadonly promptSnippet?: string;\n\t/** Optional guideline bullets appended to the default system prompt Guidelines section when this tool is active. */\n\treadonly promptGuidelines?: ReadonlyArray<string>;\n\t/** Where the tool is reachable. Omit → `direct`. */\n\treadonly exposure?: ToolExposure;\n\t/**\n\t * Repair argument shapes models commonly send before they are validated against\n\t * `parameters`. Return a copy; a throw makes the arguments invalid.\n\t */\n\treadonly prepareArguments?: (args: unknown) => unknown;\n\treadonly parameters: Params;\n\t/**\n\t * How the provider constrains the generated arguments. `{ type: \"json_schema\", strict: \"prefer\" }` sends\n\t * `parameters` in strict mode where the provider can express it and falls back to non-strict otherwise.\n\t */\n\treadonly constrainedSampling?: Message.Tool[\"constrainedSampling\"];\n\treadonly success: Success;\n\t/** Declared, model-visible failures (typed). Omit for tools that cannot fail expectedly. */\n\treadonly failure?: Failure;\n\t/** Render success for the model. Omit → executor falls back to JSON text. */\n\treadonly encodeContent?: (success: Success[\"Type\"]) => ModelContent;\n\t/** Render an expected failure for the model. Omit → executor falls back to JSON text. */\n\treadonly encodeFailureContent?: (failure: Failure[\"Type\"]) => ModelContent;\n\t/**\n\t * The `details` kept with a success, for UIs and programmatic consumers. Omit → the encoded\n\t * success. Set it when `encodeContent` already carries the payload, so it is not stored twice.\n\t */\n\treadonly encodeDetails?: (success: Success[\"Type\"]) => unknown;\n}\n\n/** A handler: validated params + context → typed success or typed failure. */\nexport type Handler<Params extends Schema.Top, Success extends Schema.Top, Failure extends Schema.Top, R = never> = (\n\tparams: Params[\"Type\"],\n\tctx: ToolCallContext,\n) => Effect.Effect<Success[\"Type\"], Failure[\"Type\"], R>;\n\n/** A definition paired with its handler (the unit the executor runs). */\nexport interface ToolImpl<\n\tName extends string = string,\n\tParams extends Schema.Top = Schema.Top,\n\tSuccess extends Schema.Top = Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n\tR = never,\n> {\n\treadonly definition: ToolDef<Name, Params, Success, Failure>;\n\treadonly handler: Handler<Params, Success, Failure, R>;\n}\n\n// Heterogeneous-collection aliases. `any` for the schema generics keeps handlers\n// of differing parameter types assignable into one array (the precise generics\n// live on the authoring helpers below).\n// biome-ignore lint/suspicious/noExplicitAny: erased schema generics for storage\nexport type AnyToolDef = ToolDef<string, any, any, any>;\n// biome-ignore lint/suspicious/noExplicitAny: erased schema generics for storage\nexport type AnyToolImpl<R = never> = ToolImpl<string, any, any, any, R>;\n\ninterface DefineInput<\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n> {\n\treadonly name: Name;\n\treadonly description: string;\n\treadonly label?: string;\n\treadonly promptSnippet?: string;\n\treadonly promptGuidelines?: ReadonlyArray<string>;\n\treadonly exposure?: ToolExposure;\n\treadonly prepareArguments?: (args: unknown) => unknown;\n\treadonly parameters: Params;\n\treadonly constrainedSampling?: Message.Tool[\"constrainedSampling\"];\n\treadonly success: Success;\n\treadonly failure?: Failure;\n\treadonly encodeContent?: (success: Success[\"Type\"]) => ModelContent;\n\treadonly encodeFailureContent?: (failure: Failure[\"Type\"]) => ModelContent;\n\treadonly encodeDetails?: (success: Success[\"Type\"]) => unknown;\n}\n\n/** Define a pure tool (handler attached later via {@link implement} or a toolkit). */\nexport const define = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n>(\n\tinput: DefineInput<Name, Params, Success, Failure>,\n): ToolDef<Name, Params, Success, Failure> => ({\n\t...input,\n});\n\n/** Attach a handler to an existing definition (the testable def/exec split). */\nexport const implement = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n\tR = never,\n>(\n\tdefinition: ToolDef<Name, Params, Success, Failure>,\n\thandler: Handler<Params, Success, Failure, R>,\n): ToolImpl<Name, Params, Success, Failure, R> => ({ definition, handler });\n\n/** Sugar for the co-located case: a definition with its handler in one object. */\nexport const make = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top = Schema.Top,\n\tR = never,\n>(\n\tinput: DefineInput<Name, Params, Success, Failure> & {\n\t\treadonly handler: Handler<Params, Success, Failure, R>;\n\t},\n): ToolImpl<Name, Params, Success, Failure, R> => {\n\tconst { handler, ...rest } = input;\n\treturn { definition: define(rest), handler };\n};\n\n/**\n * A tool ready to register: its capability requirements have been discharged, leaving only\n * the executor-provided {@link ToolProgress}. The registry and executor hold `RegisteredTool`s\n * and are non-generic (only `handle` is generic, over a progress sink's `RProgress`), so any\n * number of tools — built-in or\n * third-party/plugin — compose without a shared capability union\n */\nexport interface RegisteredTool {\n\treadonly definition: AnyToolDef;\n\treadonly handler: (\n\t\tparams: unknown,\n\t\tctx: ToolCallContext,\n\t) => Effect.Effect<unknown, ToolExecutionError, ToolProgress>;\n}\n\nconst toRegistered = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n>(\n\tdefinition: ToolDef<Name, Params, Success, Failure>,\n\thandler: Handler<Params, Success, Failure, ToolProgress>,\n): RegisteredTool => ({\n\tdefinition,\n\t// The executor decodes with `definition.parameters` before invoking this\n\t// erased handler, so restoring the authored parameter type is safe here.\n\thandler: (params, ctx) =>\n\t\thandler(params as Params[\"Type\"], ctx).pipe(\n\t\t\tEffect.mapError((cause) => new ToolExecutionError({ toolName: definition.name, cause })),\n\t\t),\n});\n\n/** Register a tool whose only requirement is the executor-provided progress service. */\nexport const register = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n>(\n\timpl: ToolImpl<Name, Params, Success, Failure, ToolProgress>,\n): RegisteredTool => toRegistered(impl.definition, impl.handler);\n\n/**\n * Discharge a tool's capability requirements into a {@link RegisteredTool}, erasing its `R`\n * (the executor still provides `ToolProgress`). This is the registration boundary: a\n * plugin/third-party tool provides its own fully-resolved capability Layer here, so the\n * registry never has to unify anyone's `R`.\n */\nexport const provide = <\n\tName extends string,\n\tParams extends Schema.Top,\n\tSuccess extends Schema.Top,\n\tFailure extends Schema.Top,\n\tR,\n>(\n\timpl: ToolImpl<Name, Params, Success, Failure, R | ToolProgress>,\n\tlayer: Layer.Layer<R>,\n): RegisteredTool =>\n\t// `Effect.provide` discharges `R`, leaving `ToolProgress`. TS can't simplify\n\t// `Exclude<ToolProgress, R>` for a generic `R`, so localize the cast before\n\t// crossing the registered-tool boundary.\n\ttoRegistered(impl.definition, ((params, ctx) => impl.handler(params, ctx).pipe(Effect.provide(layer))) as Handler<\n\t\tParams,\n\t\tSuccess,\n\t\tFailure,\n\t\tToolProgress\n\t>);\n\n/**\n * Derive a provider-safe JSON Schema object from an Effect Schema. This is the\n * single boundary that crosses into the provider wire; if a provider rejects a\n * construct, fix it here. Draft-07 inlines the root (no top-level `$ref`).\n */\nexport const toProviderJsonSchema = (schema: Schema.Top): Record<string, unknown> => {\n\t// Effect reads `Struct({})` as TS `{}` (any non-null) and emits `{ not: { type: \"null\" } }`;\n\t// providers require an object, so emit one shaped like a non-empty struct's.\n\tconst encoded = SchemaAST.toEncoded(schema.ast);\n\tif (\n\t\tSchemaAST.isObjects(encoded) &&\n\t\tencoded.propertySignatures.length === 0 &&\n\t\tencoded.indexSignatures.length === 0\n\t) {\n\t\treturn { type: \"object\", properties: {}, additionalProperties: true };\n\t}\n\treturn Schema.toStandardJSONSchemaV1(schema)[\"~standard\"].jsonSchema.input({ target: \"draft-07\" });\n};\n\n/**\n * Build the aikit `Message.Tool` wire view from a definition. The derived JSON\n * Schema object satisfies aikit's `parameters` slot structurally at runtime; the\n * single localized cast keeps aikit untouched (decision 3-A).\n */\nexport const toAikitTool = (def: AnyToolDef): Message.Tool => ({\n\tname: def.name,\n\tdescription: def.description,\n\tparameters: toProviderJsonSchema(def.parameters) as unknown as TSchema,\n\t...(def.constrainedSampling === undefined ? {} : { constrainedSampling: def.constrainedSampling }),\n});\n"],"mappings":";;;;;;;;;;;;;;;;;AA0BA,MAAa,kBAAkB,OAAO,OAAO;CAC5C,QAAQ,OAAO;CACf,UAAU,OAAO;CACjB,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO;;CAEpD,YAAY,OAAO,SAAS,OAAO,MAAM,OAAO,SAAS,CAAC,QAAQ,OAAO,CAAC,CAAC,CAAC;AAC7E,CAAC;;;;;;AAQD,MAAa,eAAe,OAAO,SAAS;CAAC;CAAU;CAAS;CAAY;CAAY;AAAQ,CAAC;;AAIjG,MAAa,YAAY,QACxB,IAAI,aAAa,KAAA,KAAa,IAAI,aAAa,YAAY,IAAI,aAAa;;AAmG7E,MAAa,UAMZ,WAC8C,EAC9C,GAAG,MACJ;;AAGA,MAAa,aAOZ,YACA,aACkD;CAAE;CAAY;AAAQ;;AAGzE,MAAa,QAOZ,UAGiD;CACjD,MAAM,EAAE,SAAS,GAAG,SAAS;CAC7B,OAAO;EAAE,YAAY,OAAO,IAAI;EAAG;CAAQ;AAC5C;AAiBA,MAAM,gBAML,YACA,aACqB;CACrB;CAGA,UAAU,QAAQ,QACjB,QAAQ,QAA0B,GAAG,CAAC,CAAC,KACtC,OAAO,UAAU,UAAU,IAAI,mBAAmB;EAAE,UAAU,WAAW;EAAM;CAAM,CAAC,CAAC,CACxF;AACF;;AAGA,MAAa,YAMZ,SACoB,aAAa,KAAK,YAAY,KAAK,OAAO;;;;;;;AAQ/D,MAAa,WAOZ,MACA,UAKA,aAAa,KAAK,cAAc,QAAQ,QAAQ,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK,OAAO,QAAQ,KAAK,CAAC,EAKnG;;;;;;AAOF,MAAa,wBAAwB,WAAgD;CAGpF,MAAM,UAAU,UAAU,UAAU,OAAO,GAAG;CAC9C,IACC,UAAU,UAAU,OAAO,KAC3B,QAAQ,mBAAmB,WAAW,KACtC,QAAQ,gBAAgB,WAAW,GAEnC,OAAO;EAAE,MAAM;EAAU,YAAY,CAAC;EAAG,sBAAsB;CAAK;CAErE,OAAO,OAAO,uBAAuB,MAAM,CAAC,CAAC,YAAY,CAAC,WAAW,MAAM,EAAE,QAAQ,WAAW,CAAC;AAClG;;;;;;AAOA,MAAa,eAAe,SAAmC;CAC9D,MAAM,IAAI;CACV,aAAa,IAAI;CACjB,YAAY,qBAAqB,IAAI,UAAU;CAC/C,GAAI,IAAI,wBAAwB,KAAA,IAAY,CAAC,IAAI,EAAE,qBAAqB,IAAI,oBAAoB;AACjG"}