@yolk-sdk/knowledge 0.1.0-canary.96 → 0.1.0-canary.98

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,11 +5,11 @@ Domain-free knowledge document/source/file/context, ingestion, hybrid search, an
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- pnpm add @yolk-sdk/knowledge@canary @yolk-sdk/agent@canary effect@4.0.0-rc.115
8
+ pnpm add @yolk-sdk/knowledge@canary @yolk-sdk/agent@canary effect@4.0.0
9
9
  ```
10
10
 
11
11
  Canary APIs are unstable. Keep all `@yolk-sdk/*` packages on the same version.
12
- Use the SDK's matching Effect version (`4.0.0-rc.115`) in host code.
12
+ Use the SDK's matching Effect version (`4.0.0`) in host code.
13
13
  Published package metadata requires Node.js 22+.
14
14
 
15
15
  ## Model
@@ -141,6 +141,13 @@ const manageTool = makeKnowledgeManageTool({
141
141
  The callbacks are host adapters and receive the agent tool context. Hosts own authorization,
142
142
  storage, scope enforcement, and safe `ToolError` mapping.
143
143
 
144
+ Both tools declare an output (`KnowledgeLookupOutput`, `KnowledgeManageOutput`) and return its JSON
145
+ encoding as `structuredContent` (dates as ISO strings) next to the text, so code mode scripts get
146
+ `{ operation: 'search', results }`, `{ operation: 'get', document }`, or
147
+ `{ operation, document: { id, slug, title } }`. A handler value that does not encode fails the call
148
+ with an `execution` `ToolError`. Unknown argument keys are model-visible validation errors with a
149
+ hint naming the allowed keys, not stripped.
150
+
144
151
  ## Ingestion semantics
145
152
 
146
153
  `ingestKnowledgeDocument` upserts a `processing` index record, extracts, chunks, embeds and
@@ -168,6 +175,8 @@ filtering, and any coordination with the content document store.
168
175
  `KnowledgeSummarizer`, and `SearchIndexStore` layers. Summary/title values may be absent, but the
169
176
  current pipeline still requires the summarizer service.
170
177
  - Own concrete extraction, embeddings, search SQL/vector storage, and upload URLs.
178
+ `@yolk-sdk/extractors/knowledge` provides a `KnowledgeExtractor` for PDF, DOCX, XLSX, PPTX, and
179
+ text files (`FileKnowledgeExtractorLayer`) on top of its Node `FileExtractor`.
171
180
  - Keep slug uniqueness scoped to the host boundary.
172
181
 
173
182
  ## Boundaries
package/dist/agent.d.mts CHANGED
@@ -1,9 +1,66 @@
1
1
  import { KnowledgeAvailability, KnowledgeDocument } from "./documents.mjs";
2
2
  import { Effect } from "effect";
3
+ import * as Schema from "effect/Schema";
3
4
  import { ToolError } from "@yolk-sdk/agent/loop";
4
5
  import { ToolRegistration } from "@yolk-sdk/agent/tools";
5
6
 
6
7
  //#region src/agent.d.ts
8
+ /** Declared output of `makeKnowledgeLookupTool`; `structuredContent` is its JSON encoding
9
+ * (`Schema.toCodecJson`: document dates become ISO strings). */
10
+ declare const KnowledgeLookupOutput: Schema.Union<readonly [Schema.Struct<{
11
+ readonly operation: Schema.Literal<"search">;
12
+ readonly results: Schema.$Array<Schema.Struct<{
13
+ readonly document: Schema.Struct<{
14
+ readonly id: Schema.brand<Schema.Trimmed, "KnowledgeDocumentId">;
15
+ readonly slug: Schema.Trimmed;
16
+ readonly title: Schema.Trimmed;
17
+ readonly purpose: Schema.Trimmed;
18
+ readonly origin: Schema.Trimmed;
19
+ readonly content: Schema.Trimmed;
20
+ readonly status: Schema.Literals<readonly ["processing", "ready", "error"]>;
21
+ readonly availability: Schema.Literals<readonly ["pinned", "searchable", "archived"]>;
22
+ readonly summary: Schema.optional<Schema.String>;
23
+ readonly errorMessage: Schema.optional<Schema.String>;
24
+ readonly reviewedAt: Schema.optional<Schema.DateTimeUtc>;
25
+ readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>;
26
+ readonly createdAt: Schema.DateTimeUtc;
27
+ readonly updatedAt: Schema.DateTimeUtc;
28
+ }>;
29
+ readonly score: Schema.optionalKey<Schema.Number>;
30
+ readonly context: Schema.optionalKey<Schema.$Array<Schema.Struct<{
31
+ readonly content: Schema.String;
32
+ }>>>;
33
+ }>>;
34
+ }>, Schema.Struct<{
35
+ readonly operation: Schema.Literal<"get">;
36
+ readonly document: Schema.Struct<{
37
+ readonly id: Schema.brand<Schema.Trimmed, "KnowledgeDocumentId">;
38
+ readonly slug: Schema.Trimmed;
39
+ readonly title: Schema.Trimmed;
40
+ readonly purpose: Schema.Trimmed;
41
+ readonly origin: Schema.Trimmed;
42
+ readonly content: Schema.Trimmed;
43
+ readonly status: Schema.Literals<readonly ["processing", "ready", "error"]>;
44
+ readonly availability: Schema.Literals<readonly ["pinned", "searchable", "archived"]>;
45
+ readonly summary: Schema.optional<Schema.String>;
46
+ readonly errorMessage: Schema.optional<Schema.String>;
47
+ readonly reviewedAt: Schema.optional<Schema.DateTimeUtc>;
48
+ readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>;
49
+ readonly createdAt: Schema.DateTimeUtc;
50
+ readonly updatedAt: Schema.DateTimeUtc;
51
+ }>;
52
+ }>]>;
53
+ type KnowledgeLookupOutput = typeof KnowledgeLookupOutput.Type;
54
+ /** Declared output of `makeKnowledgeManageTool`; `structuredContent` is its JSON encoding. */
55
+ declare const KnowledgeManageOutput: Schema.Struct<{
56
+ readonly operation: Schema.Literals<readonly ["upsert", "set_availability", "rename_slug", "delete"]>;
57
+ readonly document: Schema.Struct<{
58
+ readonly id: Schema.String;
59
+ readonly slug: Schema.String;
60
+ readonly title: Schema.String;
61
+ }>;
62
+ }>;
63
+ type KnowledgeManageOutput = typeof KnowledgeManageOutput.Type;
7
64
  type KnowledgeTarget = {
8
65
  readonly slug: string;
9
66
  readonly scope?: string;
@@ -68,5 +125,5 @@ declare const makeKnowledgeManageTool: <Context>(handlers: KnowledgeManageHandle
68
125
  readonly description?: string;
69
126
  }) => ToolRegistration<Context>;
70
127
  //#endregion
71
- export { KnowledgeLookupHandlers, KnowledgeLookupResult, KnowledgeManageHandlers, KnowledgeSavedDocument, KnowledgeTarget, makeKnowledgeLookupTool, makeKnowledgeManageTool };
128
+ export { KnowledgeLookupHandlers, KnowledgeLookupOutput, KnowledgeLookupResult, KnowledgeManageHandlers, KnowledgeManageOutput, KnowledgeSavedDocument, KnowledgeTarget, makeKnowledgeLookupTool, makeKnowledgeManageTool };
72
129
  //# sourceMappingURL=agent.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.mts","names":[],"sources":["../src/agent.ts"],"mappings":";;;;;;KA0EY,eAAA;EAAA,SACD,IAAA;EAAA,SACA,KAAK;AAAA;AAAA,KAGJ,qBAAA;EAAA,SACD,QAAA,EAAU,iBAAA;EAAA,SACV,KAAA;EAAA,SACA,OAAA,GAAU,aAAa;IAAA,SAAY,OAAA;EAAA;AAAA;AAAA,KAGlC,sBAAA;EAAA,SACD,EAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA;AAAA;AAAA,KAGC,uBAAA;EAAA,SACD,MAAA,GAAS,KAAA;IAAA,SACP,OAAA,EAAS,OAAA;IAAA,SACT,KAAA;IAAA,SACA,KAAA;IAAA,SACA,QAAA;IAAA,SACA,aAAA;EAAA,MACL,MAAA,CAAO,MAAA,CAAO,aAAA,CAAc,qBAAA,GAAwB,SAAA;EAAA,SACjD,GAAA,GAAM,KAAA;IAAA,SACJ,OAAA,EAAS,OAAA;IAAA,SACT,EAAA;IAAA,SACA,MAAA,GAAS,eAAA;EAAA,MACd,MAAA,CAAO,MAAA,CAAO,iBAAA,EAAmB,SAAA;AAAA;AAAA,KAG7B,uBAAA;EAAA,SACD,MAAA,GAAS,KAAA;IAAA,SACP,OAAA,EAAS,OAAA;IAAA,SACT,MAAA,EAAQ,eAAA;IAAA,SACR,KAAA;IAAA,SACA,OAAA;IAAA,SACA,MAAA;IAAA,SACA,OAAA;IAAA,SACA,YAAA,EAAc,qBAAA;EAAA,MACnB,MAAA,CAAO,MAAA,CAAO,sBAAA,EAAwB,SAAA;EAAA,SACnC,eAAA,GAAkB,KAAA;IAAA,SAChB,OAAA,EAAS,OAAA;IAAA,SACT,MAAA,EAAQ,eAAA;IAAA,SACR,YAAA,EAAc,qBAAA;EAAA,MACnB,MAAA,CAAO,MAAA,CAAO,sBAAA,EAAwB,SAAA;EAAA,SACnC,UAAA,GAAa,KAAA;IAAA,SACX,OAAA,EAAS,OAAA;IAAA,SACT,MAAA,EAAQ,eAAA;IAAA,SACR,QAAA;EAAA,MACL,MAAA,CAAO,MAAA,CAAO,sBAAA,EAAwB,SAAA;EAAA,SACnC,MAAA,GAAS,KAAA;IAAA,SACP,OAAA,EAAS,OAAA;IAAA,SACT,MAAA,EAAQ,eAAA;EAAA,MACb,MAAA,CAAO,MAAA,CAAO,sBAAA,EAAwB,SAAA;AAAA;AAAA,cAoDjC,uBAAA,YACX,QAAA,EAAU,uBAAA,CAAwB,OAAA,GAClC,OAAA;EAAA,SAAoB,IAAA;EAAA,SAAwB,WAAA;AAAA,MAC3C,gBAAA,CAAiB,OAAA;AAAA,cAqCP,uBAAA,YACX,QAAA,EAAU,uBAAA,CAAwB,OAAA,GAClC,OAAA;EAAA,SAAoB,IAAA;EAAA,SAAwB,WAAA;AAAA,MAC3C,gBAAA,CAAiB,OAAA"}
1
+ {"version":3,"file":"agent.d.mts","names":[],"sources":["../src/agent.ts"],"mappings":";;;;;;;;;cA6Ea,qBAAA,EAAqB,MAAA,CAAA,KAAA,WAAA,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAWtB,qBAAA,UAA+B,qBAAA,CAAsB,IAAI;;cAGxD,qBAAA,EAAqB,MAAA,CAAA,MAAA;EAAA;;;;;;;KAKtB,qBAAA,UAA+B,qBAAA,CAAsB,IAAI;AAAA,KAqBzD,eAAA;EAAA,SACD,IAAA;EAAA,SACA,KAAK;AAAA;AAAA,KAGJ,qBAAA;EAAA,SACD,QAAA,EAAU,iBAAA;EAAA,SACV,KAAA;EAAA,SACA,OAAA,GAAU,aAAa;IAAA,SAAY,OAAA;EAAA;AAAA;AAAA,KAGlC,sBAAA;EAAA,SACD,EAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA;AAAA;AAAA,KAGC,uBAAA;EAAA,SACD,MAAA,GAAS,KAAA;IAAA,SACP,OAAA,EAAS,OAAA;IAAA,SACT,KAAA;IAAA,SACA,KAAA;IAAA,SACA,QAAA;IAAA,SACA,aAAA;EAAA,MACL,MAAA,CAAO,MAAA,CAAO,aAAA,CAAc,qBAAA,GAAwB,SAAA;EAAA,SACjD,GAAA,GAAM,KAAA;IAAA,SACJ,OAAA,EAAS,OAAA;IAAA,SACT,EAAA;IAAA,SACA,MAAA,GAAS,eAAA;EAAA,MACd,MAAA,CAAO,MAAA,CAAO,iBAAA,EAAmB,SAAA;AAAA;AAAA,KAG7B,uBAAA;EAAA,SACD,MAAA,GAAS,KAAA;IAAA,SACP,OAAA,EAAS,OAAA;IAAA,SACT,MAAA,EAAQ,eAAA;IAAA,SACR,KAAA;IAAA,SACA,OAAA;IAAA,SACA,MAAA;IAAA,SACA,OAAA;IAAA,SACA,YAAA,EAAc,qBAAA;EAAA,MACnB,MAAA,CAAO,MAAA,CAAO,sBAAA,EAAwB,SAAA;EAAA,SACnC,eAAA,GAAkB,KAAA;IAAA,SAChB,OAAA,EAAS,OAAA;IAAA,SACT,MAAA,EAAQ,eAAA;IAAA,SACR,YAAA,EAAc,qBAAA;EAAA,MACnB,MAAA,CAAO,MAAA,CAAO,sBAAA,EAAwB,SAAA;EAAA,SACnC,UAAA,GAAa,KAAA;IAAA,SACX,OAAA,EAAS,OAAA;IAAA,SACT,MAAA,EAAQ,eAAA;IAAA,SACR,QAAA;EAAA,MACL,MAAA,CAAO,MAAA,CAAO,sBAAA,EAAwB,SAAA;EAAA,SACnC,MAAA,GAAS,KAAA;IAAA,SACP,OAAA,EAAS,OAAA;IAAA,SACT,MAAA,EAAQ,eAAA;EAAA,MACb,MAAA,CAAO,MAAA,CAAO,sBAAA,EAAwB,SAAA;AAAA;AAAA,cA2FjC,uBAAA,YACX,QAAA,EAAU,uBAAA,CAAwB,OAAA,GAClC,OAAA;EAAA,SAAoB,IAAA;EAAA,SAAwB,WAAA;AAAA,MAC3C,gBAAA,CAAiB,OAAA;AAAA,cA0DP,uBAAA,YACX,QAAA,EAAU,uBAAA,CAAwB,OAAA,GAClC,OAAA;EAAA,SAAoB,IAAA;EAAA,SAAwB,WAAA;AAAA,MAC3C,gBAAA,CAAiB,OAAA"}
package/dist/agent.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { KnowledgeAvailabilitySchema, NonEmptyTrimmedString, NonNegativeInteger, PositiveInteger } from "./documents.mjs";
1
+ import { KnowledgeAvailabilitySchema, KnowledgeDocumentSchema, NonEmptyTrimmedString, NonNegativeInteger, PositiveInteger } from "./documents.mjs";
2
2
  import { Effect } from "effect";
3
3
  import * as Schema from "effect/Schema";
4
4
  import { ToolError } from "@yolk-sdk/agent/loop";
5
5
  import { ToolResult } from "@yolk-sdk/agent/protocol";
6
- import { makeTool } from "@yolk-sdk/agent/tools";
6
+ import { makeTool, withToolArgumentsErrorHint } from "@yolk-sdk/agent/tools";
7
7
  //#region src/agent.ts
8
8
  const OptionalNonEmptyTrimmedString = Schema.optional(Schema.NullOr(NonEmptyTrimmedString));
9
9
  const OptionalPositiveInteger = Schema.optional(Schema.NullOr(PositiveInteger));
@@ -49,6 +49,43 @@ const KnowledgeManageParams = Schema.Union([
49
49
  target: KnowledgeTargetParamsSchema
50
50
  })
51
51
  ]);
52
+ const KnowledgeLookupResultSchema = Schema.Struct({
53
+ document: KnowledgeDocumentSchema,
54
+ score: Schema.optionalKey(Schema.Number),
55
+ context: Schema.optionalKey(Schema.Array(Schema.Struct({ content: Schema.String })))
56
+ });
57
+ /** Declared output of `makeKnowledgeLookupTool`; `structuredContent` is its JSON encoding
58
+ * (`Schema.toCodecJson`: document dates become ISO strings). */
59
+ const KnowledgeLookupOutput = Schema.Union([Schema.Struct({
60
+ operation: Schema.Literal("search"),
61
+ results: Schema.Array(KnowledgeLookupResultSchema)
62
+ }), Schema.Struct({
63
+ operation: Schema.Literal("get"),
64
+ document: KnowledgeDocumentSchema
65
+ })]);
66
+ /** Declared output of `makeKnowledgeManageTool`; `structuredContent` is its JSON encoding. */
67
+ const KnowledgeManageOutput = Schema.Struct({
68
+ operation: Schema.Literals([
69
+ "upsert",
70
+ "set_availability",
71
+ "rename_slug",
72
+ "delete"
73
+ ]),
74
+ document: Schema.Struct({
75
+ id: Schema.String,
76
+ slug: Schema.String,
77
+ title: Schema.String
78
+ })
79
+ });
80
+ const encodeLookupOutput = Schema.encodeEffect(Schema.toCodecJson(KnowledgeLookupOutput));
81
+ const encodeManageOutput = Schema.encodeEffect(Schema.toCodecJson(KnowledgeManageOutput));
82
+ /** A handler result that does not encode to the declared output is a host bug, not a model
83
+ * mistake: fail with a safe message (no values). */
84
+ const outputError = (tool) => () => new ToolError({
85
+ tool,
86
+ message: `${tool} produced a result that does not match its output schema.`,
87
+ cause: "execution"
88
+ });
52
89
  const optionalValue = (value) => value ?? void 0;
53
90
  const targetFromParams = (target) => target.scope === null || target.scope === void 0 ? { slug: target.slug } : {
54
91
  slug: target.slug,
@@ -83,13 +120,33 @@ const formatSaved = (verb, document) => [
83
120
  `slug: ${document.slug}`,
84
121
  `document_id: ${document.id}`
85
122
  ].join("\n");
123
+ const lookupResultOutput = (result) => {
124
+ const output = { document: result.document };
125
+ if (result.score !== void 0) output.score = result.score;
126
+ if (result.context !== void 0) output.context = result.context.map((chunk) => ({ content: chunk.content }));
127
+ return output;
128
+ };
129
+ const savedResult = (input) => encodeManageOutput({
130
+ operation: input.operation,
131
+ document: {
132
+ id: input.document.id,
133
+ slug: input.document.slug,
134
+ title: input.document.title
135
+ }
136
+ }).pipe(Effect.mapError(outputError(input.name)), Effect.map((structuredContent) => ToolResult.make({
137
+ toolCallId: input.callId,
138
+ content: formatSaved(input.verb, input.document),
139
+ structuredContent
140
+ })));
86
141
  const makeKnowledgeLookupTool = (handlers, options = {}) => {
142
+ const name = options.name ?? "knowledge_lookup";
87
143
  return makeTool({
88
- name: options.name ?? "knowledge_lookup",
144
+ name,
89
145
  description: options.description ?? "Look up durable knowledge. Search for semantic discovery; get when document_id or slug is known.",
90
146
  parameters: KnowledgeLookupParams,
147
+ output: KnowledgeLookupOutput,
91
148
  access: "read",
92
- invalidParamsMessage: (error) => `Invalid knowledge lookup arguments: ${error instanceof Error ? error.message : String(error)}`,
149
+ invalidParamsMessage: (error) => withToolArgumentsErrorHint(`Invalid knowledge lookup arguments: ${error instanceof Error ? error.message : String(error)}`, error),
93
150
  execute: ({ call, context, params }) => Effect.gen(function* () {
94
151
  if (params.operation === "search") {
95
152
  const results = yield* handlers.search({
@@ -99,9 +156,14 @@ const makeKnowledgeLookupTool = (handlers, options = {}) => {
99
156
  minScore: optionalValue(params.minScore),
100
157
  contextChunks: optionalValue(params.contextChunks)
101
158
  });
159
+ const structuredContent = yield* encodeLookupOutput({
160
+ operation: "search",
161
+ results: results.map(lookupResultOutput)
162
+ }).pipe(Effect.mapError(outputError(name)));
102
163
  return ToolResult.make({
103
164
  toolCallId: call.id,
104
- content: formatSearchResults(results)
165
+ content: formatSearchResults(results),
166
+ structuredContent
105
167
  });
106
168
  }
107
169
  const document = yield* handlers.get({
@@ -109,20 +171,27 @@ const makeKnowledgeLookupTool = (handlers, options = {}) => {
109
171
  id: optionalValue(params.id),
110
172
  target: optionalTargetFromParams(params.target)
111
173
  });
174
+ const structuredContent = yield* encodeLookupOutput({
175
+ operation: "get",
176
+ document
177
+ }).pipe(Effect.mapError(outputError(name)));
112
178
  return ToolResult.make({
113
179
  toolCallId: call.id,
114
- content: formatDocument(document)
180
+ content: formatDocument(document),
181
+ structuredContent
115
182
  });
116
183
  })
117
184
  });
118
185
  };
119
186
  const makeKnowledgeManageTool = (handlers, options = {}) => {
187
+ const name = options.name ?? "knowledge_manage";
120
188
  return makeTool({
121
- name: options.name ?? "knowledge_manage",
189
+ name,
122
190
  description: options.description ?? "Create, replace, pin, archive, rename, or delete durable knowledge. Use only when explicitly asked.",
123
191
  parameters: KnowledgeManageParams,
192
+ output: KnowledgeManageOutput,
124
193
  access: "write",
125
- invalidParamsMessage: (error) => `Invalid knowledge manage arguments: ${error instanceof Error ? error.message : String(error)}`,
194
+ invalidParamsMessage: (error) => withToolArgumentsErrorHint(`Invalid knowledge manage arguments: ${error instanceof Error ? error.message : String(error)}`, error),
126
195
  execute: ({ call, context, params }) => Effect.gen(function* () {
127
196
  switch (params.operation) {
128
197
  case "upsert": {
@@ -135,9 +204,12 @@ const makeKnowledgeManageTool = (handlers, options = {}) => {
135
204
  content: params.content,
136
205
  availability: params.availability
137
206
  });
138
- return ToolResult.make({
139
- toolCallId: call.id,
140
- content: formatSaved("Knowledge upserted", document)
207
+ return yield* savedResult({
208
+ name,
209
+ callId: call.id,
210
+ verb: "Knowledge upserted",
211
+ operation: "upsert",
212
+ document
141
213
  });
142
214
  }
143
215
  case "set_availability": {
@@ -146,9 +218,12 @@ const makeKnowledgeManageTool = (handlers, options = {}) => {
146
218
  target: targetFromParams(params.target),
147
219
  availability: params.availability
148
220
  });
149
- return ToolResult.make({
150
- toolCallId: call.id,
151
- content: formatSaved("Knowledge availability updated", document)
221
+ return yield* savedResult({
222
+ name,
223
+ callId: call.id,
224
+ verb: "Knowledge availability updated",
225
+ operation: "set_availability",
226
+ document
152
227
  });
153
228
  }
154
229
  case "rename_slug": {
@@ -157,9 +232,12 @@ const makeKnowledgeManageTool = (handlers, options = {}) => {
157
232
  target: targetFromParams(params.target),
158
233
  nextSlug: params.nextSlug
159
234
  });
160
- return ToolResult.make({
161
- toolCallId: call.id,
162
- content: formatSaved("Knowledge slug renamed", document)
235
+ return yield* savedResult({
236
+ name,
237
+ callId: call.id,
238
+ verb: "Knowledge slug renamed",
239
+ operation: "rename_slug",
240
+ document
163
241
  });
164
242
  }
165
243
  case "delete": {
@@ -167,9 +245,12 @@ const makeKnowledgeManageTool = (handlers, options = {}) => {
167
245
  context,
168
246
  target: targetFromParams(params.target)
169
247
  });
170
- return ToolResult.make({
171
- toolCallId: call.id,
172
- content: formatSaved("Knowledge deleted", document)
248
+ return yield* savedResult({
249
+ name,
250
+ callId: call.id,
251
+ verb: "Knowledge deleted",
252
+ operation: "delete",
253
+ document
173
254
  });
174
255
  }
175
256
  }
@@ -182,6 +263,6 @@ const makeKnowledgeManageTool = (handlers, options = {}) => {
182
263
  });
183
264
  };
184
265
  //#endregion
185
- export { makeKnowledgeLookupTool, makeKnowledgeManageTool };
266
+ export { KnowledgeLookupOutput, KnowledgeManageOutput, makeKnowledgeLookupTool, makeKnowledgeManageTool };
186
267
 
187
268
  //# sourceMappingURL=agent.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent.mjs","names":[],"sources":["../src/agent.ts"],"sourcesContent":["import { Effect } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport { ToolError } from '@yolk-sdk/agent/loop'\nimport { ToolResult } from '@yolk-sdk/agent/protocol'\nimport { makeTool, type ToolRegistration } from '@yolk-sdk/agent/tools'\nimport {\n KnowledgeAvailabilitySchema,\n NonNegativeInteger,\n NonEmptyTrimmedString,\n PositiveInteger,\n type KnowledgeAvailability,\n type KnowledgeDocument\n} from './documents.ts'\n\nconst OptionalNonEmptyTrimmedString = Schema.optional(Schema.NullOr(NonEmptyTrimmedString))\n\nconst OptionalPositiveInteger = Schema.optional(Schema.NullOr(PositiveInteger))\n\nconst OptionalNonNegativeInteger = Schema.optional(Schema.NullOr(NonNegativeInteger))\n\nconst OptionalNumber = Schema.optional(Schema.NullOr(Schema.Number))\n\nconst KnowledgeTargetParamsSchema = Schema.Struct({\n slug: NonEmptyTrimmedString,\n scope: OptionalNonEmptyTrimmedString\n})\n\nconst KnowledgeLookupParams = Schema.Union([\n Schema.Struct({\n operation: Schema.Literal('search'),\n query: NonEmptyTrimmedString,\n limit: OptionalPositiveInteger,\n minScore: OptionalNumber,\n contextChunks: OptionalNonNegativeInteger\n }),\n Schema.Struct({\n operation: Schema.Literal('get'),\n id: OptionalNonEmptyTrimmedString,\n target: Schema.optional(Schema.NullOr(KnowledgeTargetParamsSchema))\n })\n])\n\nconst KnowledgeManageParams = Schema.Union([\n Schema.Struct({\n operation: Schema.Literal('upsert'),\n target: KnowledgeTargetParamsSchema,\n title: NonEmptyTrimmedString,\n purpose: NonEmptyTrimmedString,\n origin: NonEmptyTrimmedString,\n content: NonEmptyTrimmedString,\n availability: KnowledgeAvailabilitySchema\n }),\n Schema.Struct({\n operation: Schema.Literal('set_availability'),\n target: KnowledgeTargetParamsSchema,\n availability: KnowledgeAvailabilitySchema\n }),\n Schema.Struct({\n operation: Schema.Literal('rename_slug'),\n target: KnowledgeTargetParamsSchema,\n nextSlug: NonEmptyTrimmedString\n }),\n Schema.Struct({\n operation: Schema.Literal('delete'),\n target: KnowledgeTargetParamsSchema\n })\n])\n\ntype KnowledgeTargetParams = typeof KnowledgeTargetParamsSchema.Type\n\ntype KnowledgeLookupParams = typeof KnowledgeLookupParams.Type\n\ntype KnowledgeManageParams = typeof KnowledgeManageParams.Type\n\nexport type KnowledgeTarget = {\n readonly slug: string\n readonly scope?: string\n}\n\nexport type KnowledgeLookupResult = {\n readonly document: KnowledgeDocument\n readonly score?: number\n readonly context?: ReadonlyArray<{ readonly content: string }>\n}\n\nexport type KnowledgeSavedDocument = {\n readonly id: string\n readonly slug: string\n readonly title: string\n}\n\nexport type KnowledgeLookupHandlers<Context> = {\n readonly search: (input: {\n readonly context: Context\n readonly query: string\n readonly limit?: number\n readonly minScore?: number\n readonly contextChunks?: number\n }) => Effect.Effect<ReadonlyArray<KnowledgeLookupResult>, ToolError>\n readonly get: (input: {\n readonly context: Context\n readonly id?: string\n readonly target?: KnowledgeTarget\n }) => Effect.Effect<KnowledgeDocument, ToolError>\n}\n\nexport type KnowledgeManageHandlers<Context> = {\n readonly upsert: (input: {\n readonly context: Context\n readonly target: KnowledgeTarget\n readonly title: string\n readonly purpose: string\n readonly origin: string\n readonly content: string\n readonly availability: KnowledgeAvailability\n }) => Effect.Effect<KnowledgeSavedDocument, ToolError>\n readonly setAvailability: (input: {\n readonly context: Context\n readonly target: KnowledgeTarget\n readonly availability: KnowledgeAvailability\n }) => Effect.Effect<KnowledgeSavedDocument, ToolError>\n readonly renameSlug: (input: {\n readonly context: Context\n readonly target: KnowledgeTarget\n readonly nextSlug: string\n }) => Effect.Effect<KnowledgeSavedDocument, ToolError>\n readonly delete: (input: {\n readonly context: Context\n readonly target: KnowledgeTarget\n }) => Effect.Effect<KnowledgeSavedDocument, ToolError>\n}\n\nconst optionalValue = <Value>(value: Value | null | undefined) => value ?? undefined\n\nconst targetFromParams = (target: KnowledgeTargetParams): KnowledgeTarget =>\n target.scope === null || target.scope === undefined\n ? { slug: target.slug }\n : { slug: target.slug, scope: target.scope }\n\nconst optionalTargetFromParams = (target: KnowledgeTargetParams | null | undefined) =>\n target === null || target === undefined ? undefined : targetFromParams(target)\n\nconst formatDocument = (document: KnowledgeDocument) =>\n [\n `# ${document.title}`,\n `document_id: ${document.id}`,\n `slug: ${document.slug}`,\n `purpose: ${document.purpose}`,\n `origin: ${document.origin}`,\n `availability: ${document.availability}`,\n `status: ${document.status}`,\n '',\n document.content\n ].join('\\n')\n\nconst formatSearchResults = (results: ReadonlyArray<KnowledgeLookupResult>) =>\n results.length === 0\n ? 'No knowledge matches found.'\n : results\n .map(result =>\n [\n `## ${result.document.title}`,\n `document_id: ${result.document.id}`,\n `slug: ${result.document.slug}`,\n `purpose: ${result.document.purpose}`,\n `origin: ${result.document.origin}`,\n `availability: ${result.document.availability}`,\n result.score === undefined ? undefined : `score: ${result.score}`,\n '',\n result.context?.map(chunk => chunk.content).join('\\n\\n') ?? result.document.content\n ]\n .filter(line => line !== undefined)\n .join('\\n')\n )\n .join('\\n\\n')\n\nconst formatSaved = (verb: string, document: KnowledgeSavedDocument) =>\n [verb, `title: ${document.title}`, `slug: ${document.slug}`, `document_id: ${document.id}`].join(\n '\\n'\n )\n\nexport const makeKnowledgeLookupTool = <Context>(\n handlers: KnowledgeLookupHandlers<Context>,\n options: { readonly name?: string; readonly description?: string } = {}\n): ToolRegistration<Context> => {\n const name = options.name ?? 'knowledge_lookup'\n\n return makeTool({\n name,\n description:\n options.description ??\n 'Look up durable knowledge. Search for semantic discovery; get when document_id or slug is known.',\n parameters: KnowledgeLookupParams,\n access: 'read',\n invalidParamsMessage: error =>\n `Invalid knowledge lookup arguments: ${error instanceof Error ? error.message : String(error)}`,\n execute: ({ call, context, params }) =>\n Effect.gen(function* () {\n if (params.operation === 'search') {\n const results = yield* handlers.search({\n context,\n query: params.query,\n limit: optionalValue(params.limit),\n minScore: optionalValue(params.minScore),\n contextChunks: optionalValue(params.contextChunks)\n })\n\n return ToolResult.make({ toolCallId: call.id, content: formatSearchResults(results) })\n }\n\n const document = yield* handlers.get({\n context,\n id: optionalValue(params.id),\n target: optionalTargetFromParams(params.target)\n })\n\n return ToolResult.make({ toolCallId: call.id, content: formatDocument(document) })\n })\n })\n}\n\nexport const makeKnowledgeManageTool = <Context>(\n handlers: KnowledgeManageHandlers<Context>,\n options: { readonly name?: string; readonly description?: string } = {}\n): ToolRegistration<Context> => {\n const name = options.name ?? 'knowledge_manage'\n\n return makeTool({\n name,\n description:\n options.description ??\n 'Create, replace, pin, archive, rename, or delete durable knowledge. Use only when explicitly asked.',\n parameters: KnowledgeManageParams,\n access: 'write',\n invalidParamsMessage: error =>\n `Invalid knowledge manage arguments: ${error instanceof Error ? error.message : String(error)}`,\n execute: ({ call, context, params }) =>\n Effect.gen(function* () {\n switch (params.operation) {\n case 'upsert': {\n const document = yield* handlers.upsert({\n context,\n target: targetFromParams(params.target),\n title: params.title,\n purpose: params.purpose,\n origin: params.origin,\n content: params.content,\n availability: params.availability\n })\n\n return ToolResult.make({\n toolCallId: call.id,\n content: formatSaved('Knowledge upserted', document)\n })\n }\n\n case 'set_availability': {\n const document = yield* handlers.setAvailability({\n context,\n target: targetFromParams(params.target),\n availability: params.availability\n })\n\n return ToolResult.make({\n toolCallId: call.id,\n content: formatSaved('Knowledge availability updated', document)\n })\n }\n\n case 'rename_slug': {\n const document = yield* handlers.renameSlug({\n context,\n target: targetFromParams(params.target),\n nextSlug: params.nextSlug\n })\n\n return ToolResult.make({\n toolCallId: call.id,\n content: formatSaved('Knowledge slug renamed', document)\n })\n }\n\n case 'delete': {\n const document = yield* handlers.delete({\n context,\n target: targetFromParams(params.target)\n })\n\n return ToolResult.make({\n toolCallId: call.id,\n content: formatSaved('Knowledge deleted', document)\n })\n }\n }\n\n return yield* Effect.fail(\n new ToolError({\n tool: call.name,\n message: 'Unsupported knowledge operation',\n cause: 'validation'\n })\n )\n })\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent.mjs","names":[],"sources":["../src/agent.ts"],"sourcesContent":["import { Effect } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport { ToolError } from '@yolk-sdk/agent/loop'\nimport { ToolResult } from '@yolk-sdk/agent/protocol'\nimport { makeTool, withToolArgumentsErrorHint, type ToolRegistration } from '@yolk-sdk/agent/tools'\nimport {\n KnowledgeAvailabilitySchema,\n KnowledgeDocumentSchema,\n NonNegativeInteger,\n NonEmptyTrimmedString,\n PositiveInteger,\n type KnowledgeAvailability,\n type KnowledgeDocument\n} from './documents.ts'\n\nconst OptionalNonEmptyTrimmedString = Schema.optional(Schema.NullOr(NonEmptyTrimmedString))\n\nconst OptionalPositiveInteger = Schema.optional(Schema.NullOr(PositiveInteger))\n\nconst OptionalNonNegativeInteger = Schema.optional(Schema.NullOr(NonNegativeInteger))\n\nconst OptionalNumber = Schema.optional(Schema.NullOr(Schema.Number))\n\nconst KnowledgeTargetParamsSchema = Schema.Struct({\n slug: NonEmptyTrimmedString,\n scope: OptionalNonEmptyTrimmedString\n})\n\nconst KnowledgeLookupParams = Schema.Union([\n Schema.Struct({\n operation: Schema.Literal('search'),\n query: NonEmptyTrimmedString,\n limit: OptionalPositiveInteger,\n minScore: OptionalNumber,\n contextChunks: OptionalNonNegativeInteger\n }),\n Schema.Struct({\n operation: Schema.Literal('get'),\n id: OptionalNonEmptyTrimmedString,\n target: Schema.optional(Schema.NullOr(KnowledgeTargetParamsSchema))\n })\n])\n\nconst KnowledgeManageParams = Schema.Union([\n Schema.Struct({\n operation: Schema.Literal('upsert'),\n target: KnowledgeTargetParamsSchema,\n title: NonEmptyTrimmedString,\n purpose: NonEmptyTrimmedString,\n origin: NonEmptyTrimmedString,\n content: NonEmptyTrimmedString,\n availability: KnowledgeAvailabilitySchema\n }),\n Schema.Struct({\n operation: Schema.Literal('set_availability'),\n target: KnowledgeTargetParamsSchema,\n availability: KnowledgeAvailabilitySchema\n }),\n Schema.Struct({\n operation: Schema.Literal('rename_slug'),\n target: KnowledgeTargetParamsSchema,\n nextSlug: NonEmptyTrimmedString\n }),\n Schema.Struct({\n operation: Schema.Literal('delete'),\n target: KnowledgeTargetParamsSchema\n })\n])\n\nconst KnowledgeLookupResultSchema = Schema.Struct({\n document: KnowledgeDocumentSchema,\n score: Schema.optionalKey(Schema.Number),\n context: Schema.optionalKey(Schema.Array(Schema.Struct({ content: Schema.String })))\n})\n\n/** Declared output of `makeKnowledgeLookupTool`; `structuredContent` is its JSON encoding\n * (`Schema.toCodecJson`: document dates become ISO strings). */\nexport const KnowledgeLookupOutput = Schema.Union([\n Schema.Struct({\n operation: Schema.Literal('search'),\n results: Schema.Array(KnowledgeLookupResultSchema)\n }),\n Schema.Struct({\n operation: Schema.Literal('get'),\n document: KnowledgeDocumentSchema\n })\n])\n\nexport type KnowledgeLookupOutput = typeof KnowledgeLookupOutput.Type\n\n/** Declared output of `makeKnowledgeManageTool`; `structuredContent` is its JSON encoding. */\nexport const KnowledgeManageOutput = Schema.Struct({\n operation: Schema.Literals(['upsert', 'set_availability', 'rename_slug', 'delete']),\n document: Schema.Struct({ id: Schema.String, slug: Schema.String, title: Schema.String })\n})\n\nexport type KnowledgeManageOutput = typeof KnowledgeManageOutput.Type\n\nconst encodeLookupOutput = Schema.encodeEffect(Schema.toCodecJson(KnowledgeLookupOutput))\n\nconst encodeManageOutput = Schema.encodeEffect(Schema.toCodecJson(KnowledgeManageOutput))\n\n/** A handler result that does not encode to the declared output is a host bug, not a model\n * mistake: fail with a safe message (no values). */\nconst outputError = (tool: string) => () =>\n new ToolError({\n tool,\n message: `${tool} produced a result that does not match its output schema.`,\n cause: 'execution'\n })\n\ntype KnowledgeTargetParams = typeof KnowledgeTargetParamsSchema.Type\n\ntype KnowledgeLookupParams = typeof KnowledgeLookupParams.Type\n\ntype KnowledgeManageParams = typeof KnowledgeManageParams.Type\n\nexport type KnowledgeTarget = {\n readonly slug: string\n readonly scope?: string\n}\n\nexport type KnowledgeLookupResult = {\n readonly document: KnowledgeDocument\n readonly score?: number\n readonly context?: ReadonlyArray<{ readonly content: string }>\n}\n\nexport type KnowledgeSavedDocument = {\n readonly id: string\n readonly slug: string\n readonly title: string\n}\n\nexport type KnowledgeLookupHandlers<Context> = {\n readonly search: (input: {\n readonly context: Context\n readonly query: string\n readonly limit?: number\n readonly minScore?: number\n readonly contextChunks?: number\n }) => Effect.Effect<ReadonlyArray<KnowledgeLookupResult>, ToolError>\n readonly get: (input: {\n readonly context: Context\n readonly id?: string\n readonly target?: KnowledgeTarget\n }) => Effect.Effect<KnowledgeDocument, ToolError>\n}\n\nexport type KnowledgeManageHandlers<Context> = {\n readonly upsert: (input: {\n readonly context: Context\n readonly target: KnowledgeTarget\n readonly title: string\n readonly purpose: string\n readonly origin: string\n readonly content: string\n readonly availability: KnowledgeAvailability\n }) => Effect.Effect<KnowledgeSavedDocument, ToolError>\n readonly setAvailability: (input: {\n readonly context: Context\n readonly target: KnowledgeTarget\n readonly availability: KnowledgeAvailability\n }) => Effect.Effect<KnowledgeSavedDocument, ToolError>\n readonly renameSlug: (input: {\n readonly context: Context\n readonly target: KnowledgeTarget\n readonly nextSlug: string\n }) => Effect.Effect<KnowledgeSavedDocument, ToolError>\n readonly delete: (input: {\n readonly context: Context\n readonly target: KnowledgeTarget\n }) => Effect.Effect<KnowledgeSavedDocument, ToolError>\n}\n\nconst optionalValue = <Value>(value: Value | null | undefined) => value ?? undefined\n\nconst targetFromParams = (target: KnowledgeTargetParams): KnowledgeTarget =>\n target.scope === null || target.scope === undefined\n ? { slug: target.slug }\n : { slug: target.slug, scope: target.scope }\n\nconst optionalTargetFromParams = (target: KnowledgeTargetParams | null | undefined) =>\n target === null || target === undefined ? undefined : targetFromParams(target)\n\nconst formatDocument = (document: KnowledgeDocument) =>\n [\n `# ${document.title}`,\n `document_id: ${document.id}`,\n `slug: ${document.slug}`,\n `purpose: ${document.purpose}`,\n `origin: ${document.origin}`,\n `availability: ${document.availability}`,\n `status: ${document.status}`,\n '',\n document.content\n ].join('\\n')\n\nconst formatSearchResults = (results: ReadonlyArray<KnowledgeLookupResult>) =>\n results.length === 0\n ? 'No knowledge matches found.'\n : results\n .map(result =>\n [\n `## ${result.document.title}`,\n `document_id: ${result.document.id}`,\n `slug: ${result.document.slug}`,\n `purpose: ${result.document.purpose}`,\n `origin: ${result.document.origin}`,\n `availability: ${result.document.availability}`,\n result.score === undefined ? undefined : `score: ${result.score}`,\n '',\n result.context?.map(chunk => chunk.content).join('\\n\\n') ?? result.document.content\n ]\n .filter(line => line !== undefined)\n .join('\\n')\n )\n .join('\\n\\n')\n\nconst formatSaved = (verb: string, document: KnowledgeSavedDocument) =>\n [verb, `title: ${document.title}`, `slug: ${document.slug}`, `document_id: ${document.id}`].join(\n '\\n'\n )\n\ntype KnowledgeLookupResultOutput = {\n readonly document: KnowledgeDocument\n score?: number\n context?: ReadonlyArray<{ readonly content: string }>\n}\n\nconst lookupResultOutput = (result: KnowledgeLookupResult) => {\n const output: KnowledgeLookupResultOutput = { document: result.document }\n\n if (result.score !== undefined) output.score = result.score\n\n if (result.context !== undefined) {\n output.context = result.context.map(chunk => ({ content: chunk.content }))\n }\n\n return output\n}\n\nconst savedResult = (input: {\n readonly name: string\n readonly callId: string\n readonly verb: string\n readonly operation: KnowledgeManageOutput['operation']\n readonly document: KnowledgeSavedDocument\n}) =>\n encodeManageOutput({\n operation: input.operation,\n document: { id: input.document.id, slug: input.document.slug, title: input.document.title }\n }).pipe(\n Effect.mapError(outputError(input.name)),\n Effect.map(structuredContent =>\n ToolResult.make({\n toolCallId: input.callId,\n content: formatSaved(input.verb, input.document),\n structuredContent\n })\n )\n )\n\nexport const makeKnowledgeLookupTool = <Context>(\n handlers: KnowledgeLookupHandlers<Context>,\n options: { readonly name?: string; readonly description?: string } = {}\n): ToolRegistration<Context> => {\n const name = options.name ?? 'knowledge_lookup'\n\n return makeTool({\n name,\n description:\n options.description ??\n 'Look up durable knowledge. Search for semantic discovery; get when document_id or slug is known.',\n parameters: KnowledgeLookupParams,\n output: KnowledgeLookupOutput,\n access: 'read',\n invalidParamsMessage: error =>\n withToolArgumentsErrorHint(\n `Invalid knowledge lookup arguments: ${error instanceof Error ? error.message : String(error)}`,\n error\n ),\n execute: ({ call, context, params }) =>\n Effect.gen(function* () {\n if (params.operation === 'search') {\n const results = yield* handlers.search({\n context,\n query: params.query,\n limit: optionalValue(params.limit),\n minScore: optionalValue(params.minScore),\n contextChunks: optionalValue(params.contextChunks)\n })\n\n const structuredContent = yield* encodeLookupOutput({\n operation: 'search',\n results: results.map(lookupResultOutput)\n }).pipe(Effect.mapError(outputError(name)))\n\n return ToolResult.make({\n toolCallId: call.id,\n content: formatSearchResults(results),\n structuredContent\n })\n }\n\n const document = yield* handlers.get({\n context,\n id: optionalValue(params.id),\n target: optionalTargetFromParams(params.target)\n })\n\n const structuredContent = yield* encodeLookupOutput({ operation: 'get', document }).pipe(\n Effect.mapError(outputError(name))\n )\n\n return ToolResult.make({\n toolCallId: call.id,\n content: formatDocument(document),\n structuredContent\n })\n })\n })\n}\n\nexport const makeKnowledgeManageTool = <Context>(\n handlers: KnowledgeManageHandlers<Context>,\n options: { readonly name?: string; readonly description?: string } = {}\n): ToolRegistration<Context> => {\n const name = options.name ?? 'knowledge_manage'\n\n return makeTool({\n name,\n description:\n options.description ??\n 'Create, replace, pin, archive, rename, or delete durable knowledge. Use only when explicitly asked.',\n parameters: KnowledgeManageParams,\n output: KnowledgeManageOutput,\n access: 'write',\n invalidParamsMessage: error =>\n withToolArgumentsErrorHint(\n `Invalid knowledge manage arguments: ${error instanceof Error ? error.message : String(error)}`,\n error\n ),\n execute: ({ call, context, params }) =>\n Effect.gen(function* () {\n switch (params.operation) {\n case 'upsert': {\n const document = yield* handlers.upsert({\n context,\n target: targetFromParams(params.target),\n title: params.title,\n purpose: params.purpose,\n origin: params.origin,\n content: params.content,\n availability: params.availability\n })\n\n return yield* savedResult({\n name,\n callId: call.id,\n verb: 'Knowledge upserted',\n operation: 'upsert',\n document\n })\n }\n\n case 'set_availability': {\n const document = yield* handlers.setAvailability({\n context,\n target: targetFromParams(params.target),\n availability: params.availability\n })\n\n return yield* savedResult({\n name,\n callId: call.id,\n verb: 'Knowledge availability updated',\n operation: 'set_availability',\n document\n })\n }\n\n case 'rename_slug': {\n const document = yield* handlers.renameSlug({\n context,\n target: targetFromParams(params.target),\n nextSlug: params.nextSlug\n })\n\n return yield* savedResult({\n name,\n callId: call.id,\n verb: 'Knowledge slug renamed',\n operation: 'rename_slug',\n document\n })\n }\n\n case 'delete': {\n const document = yield* handlers.delete({\n context,\n target: targetFromParams(params.target)\n })\n\n return yield* savedResult({\n name,\n callId: call.id,\n verb: 'Knowledge deleted',\n operation: 'delete',\n document\n })\n }\n }\n\n return yield* Effect.fail(\n new ToolError({\n tool: call.name,\n message: 'Unsupported knowledge operation',\n cause: 'validation'\n })\n )\n })\n })\n}\n"],"mappings":"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"}
@@ -17,8 +17,8 @@ type IngestKnowledgeDocumentInput = {
17
17
  };
18
18
  declare const ingestKnowledgeDocument: (input: IngestKnowledgeDocumentInput) => Effect.Effect<{
19
19
  readonly id: string & import("effect/Brand").Brand<"KnowledgeDocumentId">;
20
- readonly scopeId: string & import("effect/Brand").Brand<"KnowledgeScopeId">;
21
20
  readonly status: "processing" | "ready" | "error";
21
+ readonly scopeId: string & import("effect/Brand").Brand<"KnowledgeScopeId">;
22
22
  readonly source: {
23
23
  readonly _tag: "File";
24
24
  readonly ref: string;
@@ -31,13 +31,13 @@ declare const ingestKnowledgeDocument: (input: IngestKnowledgeDocumentInput) =>
31
31
  readonly _tag: "Text";
32
32
  readonly label?: string | undefined;
33
33
  };
34
+ readonly summary?: string | undefined;
35
+ readonly errorMessage?: string | undefined;
34
36
  readonly metadata?: {
35
37
  readonly [x: string]: unknown;
36
38
  } | undefined;
37
- readonly tokenCount?: number | undefined;
38
- readonly summary?: string | undefined;
39
- readonly errorMessage?: string | undefined;
40
39
  readonly title?: string | undefined;
40
+ readonly tokenCount?: number | undefined;
41
41
  readonly contentHash?: string | undefined;
42
42
  readonly chunkCount?: number | undefined;
43
43
  }, KnowledgeIngestionError, KnowledgeSummarizer | KnowledgeChunker | KnowledgeEmbedder | KnowledgeExtractor | SearchIndexStore>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yolk-sdk/knowledge",
3
- "version": "0.1.0-canary.96",
3
+ "version": "0.1.0-canary.98",
4
4
  "description": "Domain-free knowledge document/source/file/context, ingestion, hybrid search, and lookup/manage tool helpers for agents.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -104,9 +104,9 @@
104
104
  "provenance": true
105
105
  },
106
106
  "dependencies": {
107
- "effect": "4.0.0-rc.115",
107
+ "effect": "4.0.0",
108
108
  "gpt-tokenizer": "^3.4.0",
109
- "@yolk-sdk/agent": "^0.1.0-canary.96"
109
+ "@yolk-sdk/agent": "^0.1.0-canary.98"
110
110
  },
111
111
  "scripts": {
112
112
  "build": "tsdown",
package/src/agent.ts CHANGED
@@ -2,9 +2,10 @@ import { Effect } from 'effect'
2
2
  import * as Schema from 'effect/Schema'
3
3
  import { ToolError } from '@yolk-sdk/agent/loop'
4
4
  import { ToolResult } from '@yolk-sdk/agent/protocol'
5
- import { makeTool, type ToolRegistration } from '@yolk-sdk/agent/tools'
5
+ import { makeTool, withToolArgumentsErrorHint, type ToolRegistration } from '@yolk-sdk/agent/tools'
6
6
  import {
7
7
  KnowledgeAvailabilitySchema,
8
+ KnowledgeDocumentSchema,
8
9
  NonNegativeInteger,
9
10
  NonEmptyTrimmedString,
10
11
  PositiveInteger,
@@ -66,6 +67,48 @@ const KnowledgeManageParams = Schema.Union([
66
67
  })
67
68
  ])
68
69
 
70
+ const KnowledgeLookupResultSchema = Schema.Struct({
71
+ document: KnowledgeDocumentSchema,
72
+ score: Schema.optionalKey(Schema.Number),
73
+ context: Schema.optionalKey(Schema.Array(Schema.Struct({ content: Schema.String })))
74
+ })
75
+
76
+ /** Declared output of `makeKnowledgeLookupTool`; `structuredContent` is its JSON encoding
77
+ * (`Schema.toCodecJson`: document dates become ISO strings). */
78
+ export const KnowledgeLookupOutput = Schema.Union([
79
+ Schema.Struct({
80
+ operation: Schema.Literal('search'),
81
+ results: Schema.Array(KnowledgeLookupResultSchema)
82
+ }),
83
+ Schema.Struct({
84
+ operation: Schema.Literal('get'),
85
+ document: KnowledgeDocumentSchema
86
+ })
87
+ ])
88
+
89
+ export type KnowledgeLookupOutput = typeof KnowledgeLookupOutput.Type
90
+
91
+ /** Declared output of `makeKnowledgeManageTool`; `structuredContent` is its JSON encoding. */
92
+ export const KnowledgeManageOutput = Schema.Struct({
93
+ operation: Schema.Literals(['upsert', 'set_availability', 'rename_slug', 'delete']),
94
+ document: Schema.Struct({ id: Schema.String, slug: Schema.String, title: Schema.String })
95
+ })
96
+
97
+ export type KnowledgeManageOutput = typeof KnowledgeManageOutput.Type
98
+
99
+ const encodeLookupOutput = Schema.encodeEffect(Schema.toCodecJson(KnowledgeLookupOutput))
100
+
101
+ const encodeManageOutput = Schema.encodeEffect(Schema.toCodecJson(KnowledgeManageOutput))
102
+
103
+ /** A handler result that does not encode to the declared output is a host bug, not a model
104
+ * mistake: fail with a safe message (no values). */
105
+ const outputError = (tool: string) => () =>
106
+ new ToolError({
107
+ tool,
108
+ message: `${tool} produced a result that does not match its output schema.`,
109
+ cause: 'execution'
110
+ })
111
+
69
112
  type KnowledgeTargetParams = typeof KnowledgeTargetParamsSchema.Type
70
113
 
71
114
  type KnowledgeLookupParams = typeof KnowledgeLookupParams.Type
@@ -179,6 +222,45 @@ const formatSaved = (verb: string, document: KnowledgeSavedDocument) =>
179
222
  '\n'
180
223
  )
181
224
 
225
+ type KnowledgeLookupResultOutput = {
226
+ readonly document: KnowledgeDocument
227
+ score?: number
228
+ context?: ReadonlyArray<{ readonly content: string }>
229
+ }
230
+
231
+ const lookupResultOutput = (result: KnowledgeLookupResult) => {
232
+ const output: KnowledgeLookupResultOutput = { document: result.document }
233
+
234
+ if (result.score !== undefined) output.score = result.score
235
+
236
+ if (result.context !== undefined) {
237
+ output.context = result.context.map(chunk => ({ content: chunk.content }))
238
+ }
239
+
240
+ return output
241
+ }
242
+
243
+ const savedResult = (input: {
244
+ readonly name: string
245
+ readonly callId: string
246
+ readonly verb: string
247
+ readonly operation: KnowledgeManageOutput['operation']
248
+ readonly document: KnowledgeSavedDocument
249
+ }) =>
250
+ encodeManageOutput({
251
+ operation: input.operation,
252
+ document: { id: input.document.id, slug: input.document.slug, title: input.document.title }
253
+ }).pipe(
254
+ Effect.mapError(outputError(input.name)),
255
+ Effect.map(structuredContent =>
256
+ ToolResult.make({
257
+ toolCallId: input.callId,
258
+ content: formatSaved(input.verb, input.document),
259
+ structuredContent
260
+ })
261
+ )
262
+ )
263
+
182
264
  export const makeKnowledgeLookupTool = <Context>(
183
265
  handlers: KnowledgeLookupHandlers<Context>,
184
266
  options: { readonly name?: string; readonly description?: string } = {}
@@ -191,9 +273,13 @@ export const makeKnowledgeLookupTool = <Context>(
191
273
  options.description ??
192
274
  'Look up durable knowledge. Search for semantic discovery; get when document_id or slug is known.',
193
275
  parameters: KnowledgeLookupParams,
276
+ output: KnowledgeLookupOutput,
194
277
  access: 'read',
195
278
  invalidParamsMessage: error =>
196
- `Invalid knowledge lookup arguments: ${error instanceof Error ? error.message : String(error)}`,
279
+ withToolArgumentsErrorHint(
280
+ `Invalid knowledge lookup arguments: ${error instanceof Error ? error.message : String(error)}`,
281
+ error
282
+ ),
197
283
  execute: ({ call, context, params }) =>
198
284
  Effect.gen(function* () {
199
285
  if (params.operation === 'search') {
@@ -205,7 +291,16 @@ export const makeKnowledgeLookupTool = <Context>(
205
291
  contextChunks: optionalValue(params.contextChunks)
206
292
  })
207
293
 
208
- return ToolResult.make({ toolCallId: call.id, content: formatSearchResults(results) })
294
+ const structuredContent = yield* encodeLookupOutput({
295
+ operation: 'search',
296
+ results: results.map(lookupResultOutput)
297
+ }).pipe(Effect.mapError(outputError(name)))
298
+
299
+ return ToolResult.make({
300
+ toolCallId: call.id,
301
+ content: formatSearchResults(results),
302
+ structuredContent
303
+ })
209
304
  }
210
305
 
211
306
  const document = yield* handlers.get({
@@ -214,7 +309,15 @@ export const makeKnowledgeLookupTool = <Context>(
214
309
  target: optionalTargetFromParams(params.target)
215
310
  })
216
311
 
217
- return ToolResult.make({ toolCallId: call.id, content: formatDocument(document) })
312
+ const structuredContent = yield* encodeLookupOutput({ operation: 'get', document }).pipe(
313
+ Effect.mapError(outputError(name))
314
+ )
315
+
316
+ return ToolResult.make({
317
+ toolCallId: call.id,
318
+ content: formatDocument(document),
319
+ structuredContent
320
+ })
218
321
  })
219
322
  })
220
323
  }
@@ -231,9 +334,13 @@ export const makeKnowledgeManageTool = <Context>(
231
334
  options.description ??
232
335
  'Create, replace, pin, archive, rename, or delete durable knowledge. Use only when explicitly asked.',
233
336
  parameters: KnowledgeManageParams,
337
+ output: KnowledgeManageOutput,
234
338
  access: 'write',
235
339
  invalidParamsMessage: error =>
236
- `Invalid knowledge manage arguments: ${error instanceof Error ? error.message : String(error)}`,
340
+ withToolArgumentsErrorHint(
341
+ `Invalid knowledge manage arguments: ${error instanceof Error ? error.message : String(error)}`,
342
+ error
343
+ ),
237
344
  execute: ({ call, context, params }) =>
238
345
  Effect.gen(function* () {
239
346
  switch (params.operation) {
@@ -248,9 +355,12 @@ export const makeKnowledgeManageTool = <Context>(
248
355
  availability: params.availability
249
356
  })
250
357
 
251
- return ToolResult.make({
252
- toolCallId: call.id,
253
- content: formatSaved('Knowledge upserted', document)
358
+ return yield* savedResult({
359
+ name,
360
+ callId: call.id,
361
+ verb: 'Knowledge upserted',
362
+ operation: 'upsert',
363
+ document
254
364
  })
255
365
  }
256
366
 
@@ -261,9 +371,12 @@ export const makeKnowledgeManageTool = <Context>(
261
371
  availability: params.availability
262
372
  })
263
373
 
264
- return ToolResult.make({
265
- toolCallId: call.id,
266
- content: formatSaved('Knowledge availability updated', document)
374
+ return yield* savedResult({
375
+ name,
376
+ callId: call.id,
377
+ verb: 'Knowledge availability updated',
378
+ operation: 'set_availability',
379
+ document
267
380
  })
268
381
  }
269
382
 
@@ -274,9 +387,12 @@ export const makeKnowledgeManageTool = <Context>(
274
387
  nextSlug: params.nextSlug
275
388
  })
276
389
 
277
- return ToolResult.make({
278
- toolCallId: call.id,
279
- content: formatSaved('Knowledge slug renamed', document)
390
+ return yield* savedResult({
391
+ name,
392
+ callId: call.id,
393
+ verb: 'Knowledge slug renamed',
394
+ operation: 'rename_slug',
395
+ document
280
396
  })
281
397
  }
282
398
 
@@ -286,9 +402,12 @@ export const makeKnowledgeManageTool = <Context>(
286
402
  target: targetFromParams(params.target)
287
403
  })
288
404
 
289
- return ToolResult.make({
290
- toolCallId: call.id,
291
- content: formatSaved('Knowledge deleted', document)
405
+ return yield* savedResult({
406
+ name,
407
+ callId: call.id,
408
+ verb: 'Knowledge deleted',
409
+ operation: 'delete',
410
+ document
292
411
  })
293
412
  }
294
413
  }