@yolk-sdk/knowledge 0.1.0-canary.13 → 0.1.0-canary.130

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.
Files changed (97) hide show
  1. package/README.md +160 -80
  2. package/dist/agent.d.mts +118 -19
  3. package/dist/agent.d.mts.map +1 -1
  4. package/dist/agent.mjs +256 -34
  5. package/dist/agent.mjs.map +1 -1
  6. package/dist/chunking.d.mts +13 -16
  7. package/dist/chunking.d.mts.map +1 -1
  8. package/dist/chunking.mjs +4 -4
  9. package/dist/chunking.mjs.map +1 -1
  10. package/dist/context.d.mts +4 -13
  11. package/dist/context.d.mts.map +1 -1
  12. package/dist/context.mjs +17 -13
  13. package/dist/context.mjs.map +1 -1
  14. package/dist/documents.d.mts +128 -78
  15. package/dist/documents.d.mts.map +1 -1
  16. package/dist/documents.mjs +89 -61
  17. package/dist/documents.mjs.map +1 -1
  18. package/dist/embeddings.d.mts +4 -7
  19. package/dist/embeddings.d.mts.map +1 -1
  20. package/dist/embeddings.mjs +1 -2
  21. package/dist/embeddings.mjs.map +1 -1
  22. package/dist/errors.d.mts +19 -22
  23. package/dist/errors.d.mts.map +1 -1
  24. package/dist/errors.mjs +12 -13
  25. package/dist/errors.mjs.map +1 -1
  26. package/dist/extraction.d.mts +4 -7
  27. package/dist/extraction.d.mts.map +1 -1
  28. package/dist/extraction.mjs +1 -2
  29. package/dist/extraction.mjs.map +1 -1
  30. package/dist/files.d.mts +19 -0
  31. package/dist/files.d.mts.map +1 -0
  32. package/dist/files.mjs +6 -0
  33. package/dist/files.mjs.map +1 -0
  34. package/dist/index.d.mts +4 -4
  35. package/dist/index.mjs +4 -4
  36. package/dist/ingestion.d.mts +21 -23
  37. package/dist/ingestion.d.mts.map +1 -1
  38. package/dist/ingestion.mjs +12 -17
  39. package/dist/ingestion.mjs.map +1 -1
  40. package/dist/search.d.mts +13 -17
  41. package/dist/search.d.mts.map +1 -1
  42. package/dist/search.mjs +9 -12
  43. package/dist/search.mjs.map +1 -1
  44. package/dist/store.d.mts +92 -29
  45. package/dist/store.d.mts.map +1 -1
  46. package/dist/store.mjs +3 -3
  47. package/dist/store.mjs.map +1 -1
  48. package/dist/summarization.d.mts +6 -9
  49. package/dist/summarization.d.mts.map +1 -1
  50. package/dist/summarization.mjs +1 -2
  51. package/dist/summarization.mjs.map +1 -1
  52. package/package.json +11 -41
  53. package/src/agent.ts +393 -65
  54. package/src/chunking.ts +27 -8
  55. package/src/context.ts +21 -16
  56. package/src/documents.ts +140 -71
  57. package/src/errors.ts +4 -4
  58. package/src/extraction.ts +4 -3
  59. package/src/files.ts +24 -0
  60. package/src/index.ts +6 -3
  61. package/src/ingestion.ts +46 -27
  62. package/src/search.ts +90 -62
  63. package/src/store.ts +139 -25
  64. package/src/summarization.ts +4 -3
  65. package/dist/artifacts.d.mts +0 -37
  66. package/dist/artifacts.d.mts.map +0 -1
  67. package/dist/artifacts.mjs +0 -28
  68. package/dist/artifacts.mjs.map +0 -1
  69. package/dist/links.d.mts +0 -17
  70. package/dist/links.d.mts.map +0 -1
  71. package/dist/links.mjs +0 -24
  72. package/dist/links.mjs.map +0 -1
  73. package/dist/provenance.d.mts +0 -20
  74. package/dist/provenance.d.mts.map +0 -1
  75. package/dist/provenance.mjs +0 -26
  76. package/dist/provenance.mjs.map +0 -1
  77. package/dist/records.d.mts +0 -59
  78. package/dist/records.d.mts.map +0 -1
  79. package/dist/records.mjs +0 -64
  80. package/dist/records.mjs.map +0 -1
  81. package/dist/representations.d.mts +0 -36
  82. package/dist/representations.d.mts.map +0 -1
  83. package/dist/representations.mjs +0 -44
  84. package/dist/representations.mjs.map +0 -1
  85. package/dist/search-store.d.mts +0 -77
  86. package/dist/search-store.d.mts.map +0 -1
  87. package/dist/search-store.mjs +0 -7
  88. package/dist/search-store.mjs.map +0 -1
  89. package/dist/vector-store.d.mts +0 -3
  90. package/dist/vector-store.mjs +0 -2
  91. package/src/artifacts.ts +0 -48
  92. package/src/links.ts +0 -23
  93. package/src/provenance.ts +0 -25
  94. package/src/records.ts +0 -76
  95. package/src/representations.ts +0 -51
  96. package/src/search-store.ts +0 -98
  97. package/src/vector-store.ts +0 -6
package/dist/agent.mjs CHANGED
@@ -1,45 +1,267 @@
1
- import { packKnowledgeSearchContext } from "./search.mjs";
1
+ import { KnowledgeAvailabilitySchema, KnowledgeDocumentSchema, NonEmptyTrimmedString, NonNegativeInteger, PositiveInteger } from "./documents.mjs";
2
2
  import { Effect } from "effect";
3
- import * as Schema$1 from "effect/Schema";
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";
7
- //#region src/agent.ts
8
- const defaultKnowledgeAgentContextOptions = { maxPinnedContextCharacters: 6e3 };
9
- const KnowledgeSearchToolParams = Schema$1.Struct({ query: Schema$1.Trimmed.pipe(Schema$1.check(Schema$1.isNonEmpty()), Schema$1.annotate({ description: "Search query for the configured knowledge search." })) });
10
- const isToolError = Schema$1.is(ToolError);
11
- const resolveScope = (resolver, context) => {
12
- if (typeof resolver === "function") return resolver(context);
13
- return Effect.succeed(resolver);
6
+ import { makeTool, withToolArgumentsErrorHint } from "@yolk-sdk/agent/tools";
7
+ // src/agent.ts
8
+ const OptionalNonEmptyTrimmedString = Schema.optional(Schema.NullOr(NonEmptyTrimmedString));
9
+ const OptionalPositiveInteger = Schema.optional(Schema.NullOr(PositiveInteger));
10
+ const OptionalNonNegativeInteger = Schema.optional(Schema.NullOr(NonNegativeInteger));
11
+ const OptionalNumber = Schema.optional(Schema.NullOr(Schema.Number));
12
+ const KnowledgeTargetParamsSchema = Schema.Struct({
13
+ slug: NonEmptyTrimmedString,
14
+ scope: OptionalNonEmptyTrimmedString
15
+ });
16
+ const KnowledgeLookupParams = Schema.Union([Schema.Struct({
17
+ operation: Schema.Literal("search"),
18
+ query: NonEmptyTrimmedString,
19
+ limit: OptionalPositiveInteger,
20
+ minScore: OptionalNumber,
21
+ contextChunks: OptionalNonNegativeInteger
22
+ }), Schema.Struct({
23
+ operation: Schema.Literal("get"),
24
+ id: OptionalNonEmptyTrimmedString,
25
+ target: Schema.optional(Schema.NullOr(KnowledgeTargetParamsSchema))
26
+ })]);
27
+ const KnowledgeManageParams = Schema.Union([
28
+ Schema.Struct({
29
+ operation: Schema.Literal("upsert"),
30
+ target: KnowledgeTargetParamsSchema,
31
+ title: NonEmptyTrimmedString,
32
+ purpose: NonEmptyTrimmedString,
33
+ origin: NonEmptyTrimmedString,
34
+ content: NonEmptyTrimmedString,
35
+ availability: KnowledgeAvailabilitySchema
36
+ }),
37
+ Schema.Struct({
38
+ operation: Schema.Literal("set_availability"),
39
+ target: KnowledgeTargetParamsSchema,
40
+ availability: KnowledgeAvailabilitySchema
41
+ }),
42
+ Schema.Struct({
43
+ operation: Schema.Literal("rename_slug"),
44
+ target: KnowledgeTargetParamsSchema,
45
+ nextSlug: NonEmptyTrimmedString
46
+ }),
47
+ Schema.Struct({
48
+ operation: Schema.Literal("delete"),
49
+ target: KnowledgeTargetParamsSchema
50
+ })
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
+ });
89
+ const optionalValue = (value) => value ?? void 0;
90
+ const targetFromParams = (target) => target.scope === null || target.scope === void 0 ? { slug: target.slug } : {
91
+ slug: target.slug,
92
+ scope: target.scope
14
93
  };
15
- const makeKnowledgeSearchTool = (searcher, options) => {
94
+ const optionalTargetFromParams = (target) => target === null || target === void 0 ? void 0 : targetFromParams(target);
95
+ const formatDocument = (document) => [
96
+ `# ${document.title}`,
97
+ `document_id: ${document.id}`,
98
+ `slug: ${document.slug}`,
99
+ `purpose: ${document.purpose}`,
100
+ `origin: ${document.origin}`,
101
+ `availability: ${document.availability}`,
102
+ `status: ${document.status}`,
103
+ "",
104
+ document.content
105
+ ].join("\n");
106
+ const formatSearchResults = (results) => results.length === 0 ? "No knowledge matches found." : results.map((result) => [
107
+ `## ${result.document.title}`,
108
+ `document_id: ${result.document.id}`,
109
+ `slug: ${result.document.slug}`,
110
+ `purpose: ${result.document.purpose}`,
111
+ `origin: ${result.document.origin}`,
112
+ `availability: ${result.document.availability}`,
113
+ result.score === void 0 ? void 0 : `score: ${result.score}`,
114
+ "",
115
+ result.context?.map((chunk) => chunk.content).join("\n\n") ?? result.document.content
116
+ ].filter((line) => line !== void 0).join("\n")).join("\n\n");
117
+ const formatSaved = (verb, document) => [
118
+ verb,
119
+ `title: ${document.title}`,
120
+ `slug: ${document.slug}`,
121
+ `document_id: ${document.id}`
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
+ })));
141
+ const makeKnowledgeLookupTool = (handlers, options = {}) => {
142
+ const name = options.name ?? "knowledge_lookup";
16
143
  return makeTool({
17
- name: options.name ?? "search_knowledge",
18
- description: options.description ?? "Search the configured knowledge search.",
19
- parameters: KnowledgeSearchToolParams,
144
+ name,
145
+ description: options.description ?? "Look up durable knowledge. Search for semantic discovery; get when document_id or slug is known.",
146
+ parameters: KnowledgeLookupParams,
147
+ output: KnowledgeLookupOutput,
20
148
  access: "read",
21
- invalidParamsMessage: (error) => error instanceof Error ? error.message : String(error),
22
- execute: (input) => resolveScope(options.scope, input.context).pipe(Effect.flatMap((scope) => searcher.search({
23
- scope,
24
- query: input.params.query,
25
- limit: options.limit,
26
- minScore: options.minScore,
27
- contextChunks: options.contextChunks
28
- })), Effect.map((results) => packKnowledgeSearchContext(input.params.query, results)), Effect.map((context) => ToolResult.make({
29
- toolCallId: input.call.id,
30
- content: context.text,
31
- structuredContent: context
32
- })), Effect.mapError((error) => {
33
- if (isToolError(error)) return error;
34
- return new ToolError({
35
- tool: input.call.name,
36
- message: error.message,
37
- cause: "execution"
149
+ invalidParamsMessage: (error) => withToolArgumentsErrorHint(`Invalid knowledge lookup arguments: ${error instanceof Error ? error.message : String(error)}`, error),
150
+ execute: ({ call, context, params }) => Effect.gen(function* () {
151
+ if (params.operation === "search") {
152
+ const results = yield* handlers.search({
153
+ context,
154
+ query: params.query,
155
+ limit: optionalValue(params.limit),
156
+ minScore: optionalValue(params.minScore),
157
+ contextChunks: optionalValue(params.contextChunks)
158
+ });
159
+ const structuredContent = yield* encodeLookupOutput({
160
+ operation: "search",
161
+ results: results.map(lookupResultOutput)
162
+ }).pipe(Effect.mapError(outputError(name)));
163
+ return ToolResult.make({
164
+ toolCallId: call.id,
165
+ content: formatSearchResults(results),
166
+ structuredContent
167
+ });
168
+ }
169
+ const document = yield* handlers.get({
170
+ context,
171
+ id: optionalValue(params.id),
172
+ target: optionalTargetFromParams(params.target)
173
+ });
174
+ const structuredContent = yield* encodeLookupOutput({
175
+ operation: "get",
176
+ document
177
+ }).pipe(Effect.mapError(outputError(name)));
178
+ return ToolResult.make({
179
+ toolCallId: call.id,
180
+ content: formatDocument(document),
181
+ structuredContent
38
182
  });
39
- }))
183
+ })
184
+ });
185
+ };
186
+ const makeKnowledgeManageTool = (handlers, options = {}) => {
187
+ const name = options.name ?? "knowledge_manage";
188
+ return makeTool({
189
+ name,
190
+ description: options.description ?? "Create, replace, pin, archive, rename, or delete durable knowledge. Use only when explicitly asked.",
191
+ parameters: KnowledgeManageParams,
192
+ output: KnowledgeManageOutput,
193
+ access: "write",
194
+ invalidParamsMessage: (error) => withToolArgumentsErrorHint(`Invalid knowledge manage arguments: ${error instanceof Error ? error.message : String(error)}`, error),
195
+ execute: ({ call, context, params }) => Effect.gen(function* () {
196
+ switch (params.operation) {
197
+ case "upsert": {
198
+ const document = yield* handlers.upsert({
199
+ context,
200
+ target: targetFromParams(params.target),
201
+ title: params.title,
202
+ purpose: params.purpose,
203
+ origin: params.origin,
204
+ content: params.content,
205
+ availability: params.availability
206
+ });
207
+ return yield* savedResult({
208
+ name,
209
+ callId: call.id,
210
+ verb: "Knowledge upserted",
211
+ operation: "upsert",
212
+ document
213
+ });
214
+ }
215
+ case "set_availability": {
216
+ const document = yield* handlers.setAvailability({
217
+ context,
218
+ target: targetFromParams(params.target),
219
+ availability: params.availability
220
+ });
221
+ return yield* savedResult({
222
+ name,
223
+ callId: call.id,
224
+ verb: "Knowledge availability updated",
225
+ operation: "set_availability",
226
+ document
227
+ });
228
+ }
229
+ case "rename_slug": {
230
+ const document = yield* handlers.renameSlug({
231
+ context,
232
+ target: targetFromParams(params.target),
233
+ nextSlug: params.nextSlug
234
+ });
235
+ return yield* savedResult({
236
+ name,
237
+ callId: call.id,
238
+ verb: "Knowledge slug renamed",
239
+ operation: "rename_slug",
240
+ document
241
+ });
242
+ }
243
+ case "delete": {
244
+ const document = yield* handlers.delete({
245
+ context,
246
+ target: targetFromParams(params.target)
247
+ });
248
+ return yield* savedResult({
249
+ name,
250
+ callId: call.id,
251
+ verb: "Knowledge deleted",
252
+ operation: "delete",
253
+ document
254
+ });
255
+ }
256
+ }
257
+ return yield* Effect.fail(new ToolError({
258
+ tool: call.name,
259
+ message: "Unsupported knowledge operation",
260
+ cause: "validation"
261
+ }));
262
+ })
40
263
  });
41
264
  };
42
- //#endregion
43
- export { defaultKnowledgeAgentContextOptions, makeKnowledgeSearchTool };
265
+ export { KnowledgeLookupOutput, KnowledgeManageOutput, makeKnowledgeLookupTool, makeKnowledgeManageTool };
44
266
 
45
267
  //# sourceMappingURL=agent.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent.mjs","names":["Schema"],"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 type { KnowledgeScope } from './records.ts'\nimport type { KnowledgeSearchScope } from './documents.ts'\nimport type { KnowledgeSearcher } from './search.ts'\nimport { packKnowledgeSearchContext } from './search.ts'\n\nexport type ResolveKnowledgeScope<Context> = (context: Context) => KnowledgeScope\n\nexport type KnowledgeAgentContextOptions = {\n readonly maxPinnedContextCharacters: number\n}\n\nexport const defaultKnowledgeAgentContextOptions: KnowledgeAgentContextOptions = {\n maxPinnedContextCharacters: 6000\n}\n\nconst KnowledgeSearchToolParams = Schema.Struct({\n query: Schema.Trimmed.pipe(\n Schema.check(Schema.isNonEmpty()),\n Schema.annotate({ description: 'Search query for the configured knowledge search.' })\n )\n})\n\nconst isToolError = Schema.is(ToolError)\n\nexport type KnowledgeSearchToolScopeResolver<Context> =\n | KnowledgeSearchScope\n | ((context: Context) => Effect.Effect<KnowledgeSearchScope, ToolError>)\n\nexport type MakeKnowledgeSearchToolOptions<Context> = {\n readonly scope: KnowledgeSearchToolScopeResolver<Context>\n readonly name?: string\n readonly description?: string\n readonly limit?: number\n readonly minScore?: number\n readonly contextChunks?: number\n}\n\nconst resolveScope = <Context>(resolver: KnowledgeSearchToolScopeResolver<Context>, context: Context) => {\n if (typeof resolver === 'function') {\n return resolver(context)\n }\n\n return Effect.succeed(resolver)\n}\n\nexport const makeKnowledgeSearchTool = <Context>(\n searcher: KnowledgeSearcher,\n options: MakeKnowledgeSearchToolOptions<Context>\n): ToolRegistration<Context> => {\n const name = options.name ?? 'search_knowledge'\n\n return makeTool({\n name,\n description: options.description ?? 'Search the configured knowledge search.',\n parameters: KnowledgeSearchToolParams,\n access: 'read',\n invalidParamsMessage: error => error instanceof Error ? error.message : String(error),\n execute: input =>\n resolveScope(options.scope, input.context).pipe(\n Effect.flatMap(scope =>\n searcher.search({\n scope,\n query: input.params.query,\n limit: options.limit,\n minScore: options.minScore,\n contextChunks: options.contextChunks\n })\n ),\n Effect.map(results => packKnowledgeSearchContext(input.params.query, results)),\n Effect.map(\n context =>\n ToolResult.make({\n toolCallId: input.call.id,\n content: context.text,\n structuredContent: context\n })\n ),\n Effect.mapError(error => {\n if (isToolError(error)) {\n return error\n }\n\n return new ToolError({\n tool: input.call.name,\n message: error.message,\n cause: 'execution'\n })\n })\n )\n })\n}\n"],"mappings":";;;;;;;AAgBA,MAAa,sCAAoE,EAC/E,4BAA4B,IAC9B;AAEA,MAAM,4BAA4BA,SAAO,OAAO,EAC9C,OAAOA,SAAO,QAAQ,KACpBA,SAAO,MAAMA,SAAO,WAAW,CAAC,GAChCA,SAAO,SAAS,EAAE,aAAa,oDAAoD,CAAC,CACtF,EACF,CAAC;AAED,MAAM,cAAcA,SAAO,GAAG,SAAS;AAevC,MAAM,gBAAyB,UAAqD,YAAqB;CACvG,IAAI,OAAO,aAAa,YACtB,OAAO,SAAS,OAAO;CAGzB,OAAO,OAAO,QAAQ,QAAQ;AAChC;AAEA,MAAa,2BACX,UACA,YAC8B;CAG9B,OAAO,SAAS;EACd,MAHW,QAAQ,QAAQ;EAI3B,aAAa,QAAQ,eAAe;EACpC,YAAY;EACZ,QAAQ;EACR,uBAAsB,UAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACpF,UAAS,UACP,aAAa,QAAQ,OAAO,MAAM,OAAO,EAAE,KACzC,OAAO,SAAQ,UACb,SAAS,OAAO;GACd;GACA,OAAO,MAAM,OAAO;GACpB,OAAO,QAAQ;GACf,UAAU,QAAQ;GAClB,eAAe,QAAQ;EACzB,CAAC,CACH,GACA,OAAO,KAAI,YAAW,2BAA2B,MAAM,OAAO,OAAO,OAAO,CAAC,GAC7E,OAAO,KACL,YACE,WAAW,KAAK;GACd,YAAY,MAAM,KAAK;GACvB,SAAS,QAAQ;GACjB,mBAAmB;EACrB,CAAC,CACL,GACA,OAAO,UAAS,UAAS;GACvB,IAAI,YAAY,KAAK,GACnB,OAAO;GAGT,OAAO,IAAI,UAAU;IACnB,MAAM,MAAM,KAAK;IACjB,SAAS,MAAM;IACf,OAAO;GACT,CAAC;EACH,CAAC,CACH;CACJ,CAAC;AACH"}
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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"}
@@ -1,25 +1,23 @@
1
- import { KnowledgeChunk, KnowledgeMetadata } from "./documents.mjs";
1
+ import { KnowledgeChunk, KnowledgeDocumentId, KnowledgeMetadata, KnowledgeScopeId } from "./documents.mjs";
2
2
  import { KnowledgeChunkingError } from "./errors.mjs";
3
3
  import { Context, Effect, Layer } from "effect";
4
-
5
- //#region src/chunking.d.ts
6
- type ChunkKnowledgeDocumentInput = {
7
- readonly collectionId: string;
8
- readonly documentId: string;
4
+ export type ChunkKnowledgeDocumentInput = {
5
+ readonly scopeId: KnowledgeScopeId;
6
+ readonly documentId: KnowledgeDocumentId;
9
7
  readonly content: string;
10
8
  readonly maxTokens?: number;
11
9
  readonly metadata?: KnowledgeMetadata;
12
10
  };
13
- type KnowledgeChunkerApi = {
11
+ export type KnowledgeChunkerApi = {
14
12
  readonly chunk: (input: ChunkKnowledgeDocumentInput) => Effect.Effect<ReadonlyArray<KnowledgeChunk>, KnowledgeChunkingError>;
15
13
  };
16
14
  declare const KnowledgeChunker_base: Context.ServiceClass<KnowledgeChunker, "@yolk-sdk/knowledge/KnowledgeChunker", KnowledgeChunkerApi>;
17
- declare class KnowledgeChunker extends KnowledgeChunker_base {}
18
- declare const countKnowledgeChunkTokens: (text: string) => number;
19
- declare const chunkKnowledgeText: (input: ChunkKnowledgeDocumentInput, maxTokens: number) => Effect.Effect<{
15
+ export declare class KnowledgeChunker extends KnowledgeChunker_base {}
16
+ export declare const countKnowledgeChunkTokens: (text: string) => number;
17
+ export declare const chunkKnowledgeText: (input: ChunkKnowledgeDocumentInput, maxTokens: number) => Effect.Effect<{
20
18
  id: string;
21
- collectionId: string;
22
- documentId: string;
19
+ scopeId: string & import("effect/Brand").Brand<"KnowledgeScopeId">;
20
+ documentId: string & import("effect/Brand").Brand<"KnowledgeDocumentId">;
23
21
  content: string;
24
22
  position: number;
25
23
  tokenCount: number;
@@ -27,12 +25,11 @@ declare const chunkKnowledgeText: (input: ChunkKnowledgeDocumentInput, maxTokens
27
25
  readonly [x: string]: unknown;
28
26
  } | undefined;
29
27
  }[], KnowledgeChunkingError, never>;
30
- declare const makeDefaultKnowledgeChunker: (input: {
28
+ export declare const makeDefaultKnowledgeChunker: (input: {
31
29
  readonly maxTokens: number;
32
30
  }) => KnowledgeChunkerApi;
33
- declare const DefaultKnowledgeChunkerLive: (input?: {
31
+ export declare const DefaultKnowledgeChunkerLive: (input?: {
34
32
  readonly maxTokens: number;
35
33
  }) => Layer.Layer<KnowledgeChunker, never, never>;
36
- //#endregion
37
- export { ChunkKnowledgeDocumentInput, DefaultKnowledgeChunkerLive, KnowledgeChunker, KnowledgeChunkerApi, chunkKnowledgeText, countKnowledgeChunkTokens, makeDefaultKnowledgeChunker };
34
+ export {};
38
35
  //# sourceMappingURL=chunking.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chunking.d.mts","names":[],"sources":["../src/chunking.ts"],"mappings":";;;;;KASY,2BAAA;EAAA,SACD,YAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA;EAAA,SACA,QAAA,GAAW,iBAAiB;AAAA;AAAA,KAG3B,mBAAA;EAAA,SACD,KAAA,GACP,KAAA,EAAO,2BAAA,KACJ,MAAA,CAAO,MAAA,CAAO,aAAA,CAAc,cAAA,GAAiB,sBAAA;AAAA;AAAA,cACnD,qBAAA;cAEY,gBAAA,SAAyB,qBAErC;AAAA,cAEY,yBAAA,GAA6B,IAAY;AAAA,cA+GzC,kBAAA,GAAsB,KAAA,EAAO,2BAAA,EAA6B,SAAA,aAAiB,MAAA,CAAA,MAAA;;;;;;;;;;;cA+B3E,2BAAA,GAA+B,KAAA;EAAA,SAAkB,SAAA;AAAA,MAAsB,mBAElF;AAAA,cAEW,2BAAA,GAA+B,KAAA;EAAA,SAAkB,SAAA;AAAA,MAAwC,KAAA,CAAA,KAAA,CAAA,gBAAA"}
1
+ {"version":3,"file":"chunking.d.mts","names":[],"sources":["../src/chunking.ts"],"mappings":";;;YAgBY;WACD,SAAS;WACT,YAAY;WACZ;WACA;WACA,WAAW;;YAGV;WACD,QACP,OAAO,gCACJ,OAAO,OAAO,cAAc,iBAAiB;;;qBAGvC,yBAAyB;qBAIzB,4BAAyB;qBAqHzB,qBAAkB,OAAW,6BAA2B,sBAAmB,OAAA;;;;;;;;;;KAgCpF;qBAES,8BAA2B;WAC7B;MACP;qBAIS,8BAA2B;WACpB;MAAmB,MAAA,MAAA"}
package/dist/chunking.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { KnowledgeChunkingError } from "./errors.mjs";
2
2
  import { Context, Effect, Layer } from "effect";
3
3
  import { countTokens, decode, encode } from "gpt-tokenizer/encoding/o200k_base";
4
- //#region src/chunking.ts
4
+ // src/chunking.ts
5
5
  const SENTENCE_PATTERN = /[^.!?]+[.!?]+(?:["')\]]+)?\s*|[^.!?]+$/g;
6
6
  const PARAGRAPH_BREAK_PATTERN = /(\n{2,})/;
7
7
  const WORD_PATTERN = /\S+\s*/g;
@@ -73,11 +73,12 @@ const chunkKnowledgeText = (input, maxTokens) => Effect.gen(function* () {
73
73
  if (!Number.isInteger(maxTokens) || maxTokens < 1) return yield* Effect.fail(new KnowledgeChunkingError({ message: "Chunk maxTokens must be a positive integer" }));
74
74
  const sanitized = sanitizeText(input.content);
75
75
  if (sanitized.length === 0) return yield* Effect.fail(new KnowledgeChunkingError({ message: "Cannot chunk empty content" }));
76
- const contents = buildChunkContents(splitUnitsBySize(splitSentences(sanitized), maxTokens), maxTokens);
76
+ const units = splitUnitsBySize(splitSentences(sanitized), maxTokens);
77
+ const contents = buildChunkContents(units, maxTokens);
77
78
  if (contents.length === 0) return yield* Effect.fail(new KnowledgeChunkingError({ message: "No chunks produced" }));
78
79
  return contents.map((content, position) => ({
79
80
  id: `${input.documentId}:chunk:${position}`,
80
- collectionId: input.collectionId,
81
+ scopeId: input.scopeId,
81
82
  documentId: input.documentId,
82
83
  content,
83
84
  position,
@@ -87,7 +88,6 @@ const chunkKnowledgeText = (input, maxTokens) => Effect.gen(function* () {
87
88
  });
88
89
  const makeDefaultKnowledgeChunker = (input) => ({ chunk: (document) => chunkKnowledgeText(document, document.maxTokens ?? input.maxTokens) });
89
90
  const DefaultKnowledgeChunkerLive = (input = { maxTokens: 512 }) => Layer.succeed(KnowledgeChunker, makeDefaultKnowledgeChunker(input));
90
- //#endregion
91
91
  export { DefaultKnowledgeChunkerLive, KnowledgeChunker, chunkKnowledgeText, countKnowledgeChunkTokens, makeDefaultKnowledgeChunker };
92
92
 
93
93
  //# sourceMappingURL=chunking.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"chunking.mjs","names":[],"sources":["../src/chunking.ts"],"sourcesContent":["import { Context, Effect, Layer } from 'effect'\nimport { countTokens, decode, encode } from 'gpt-tokenizer/encoding/o200k_base'\nimport type { KnowledgeChunk, KnowledgeMetadata } from './documents.ts'\nimport { KnowledgeChunkingError } from './errors.ts'\n\nconst SENTENCE_PATTERN = /[^.!?]+[.!?]+(?:[\"')\\]]+)?\\s*|[^.!?]+$/g\nconst PARAGRAPH_BREAK_PATTERN = /(\\n{2,})/\nconst WORD_PATTERN = /\\S+\\s*/g\n\nexport type ChunkKnowledgeDocumentInput = {\n readonly collectionId: string\n readonly documentId: string\n readonly content: string\n readonly maxTokens?: number\n readonly metadata?: KnowledgeMetadata\n}\n\nexport type KnowledgeChunkerApi = {\n readonly chunk: (\n input: ChunkKnowledgeDocumentInput\n ) => Effect.Effect<ReadonlyArray<KnowledgeChunk>, KnowledgeChunkingError>\n}\n\nexport class KnowledgeChunker extends Context.Service<KnowledgeChunker, KnowledgeChunkerApi>()(\n '@yolk-sdk/knowledge/KnowledgeChunker'\n) {}\n\nexport const countKnowledgeChunkTokens = (text: string) => countTokens(text)\n\nconst sanitizeText = (text: string) =>\n text\n .replace(/\\r\\n/g, '\\n')\n .replace(/[\\t ]+/g, ' ')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim()\n\nconst splitSentences = (text: string) =>\n text\n .split(PARAGRAPH_BREAK_PATTERN)\n .flatMap(part => {\n if (part.length === 0) {\n return []\n }\n\n if (/^\\n{2,}$/.test(part)) {\n return ['\\n\\n']\n }\n\n return part.match(SENTENCE_PATTERN) ?? [part]\n })\n .filter(unit => unit.length > 0)\n\nconst splitEncodedTokens = (text: string, maxTokens: number) => {\n const tokens = encode(text)\n return Array.from({ length: Math.ceil(tokens.length / maxTokens) }, (_, index) =>\n decode(tokens.slice(index * maxTokens, index * maxTokens + maxTokens)).trim()\n ).filter(chunk => chunk.length > 0)\n}\n\nconst splitOversizedUnit = (text: string, maxTokens: number) => {\n const words = text.match(WORD_PATTERN) ?? []\n const chunks: string[] = []\n let current = ''\n let currentTokenCount = 0\n\n for (const word of words) {\n const wordTokenCount = countTokens(word)\n\n if (wordTokenCount > maxTokens) {\n const currentChunk = current.trim()\n if (currentChunk.length > 0) {\n chunks.push(currentChunk)\n }\n\n chunks.push(...splitEncodedTokens(word, maxTokens))\n current = ''\n currentTokenCount = 0\n continue\n }\n\n if (currentTokenCount > 0 && currentTokenCount + wordTokenCount > maxTokens) {\n const currentChunk = current.trim()\n if (currentChunk.length > 0) {\n chunks.push(currentChunk)\n }\n\n current = word\n currentTokenCount = wordTokenCount\n continue\n }\n\n current = `${current}${word}`\n currentTokenCount += wordTokenCount\n }\n\n const finalChunk = current.trim()\n if (finalChunk.length > 0) {\n chunks.push(finalChunk)\n }\n\n return chunks\n}\n\nconst splitUnitsBySize = (units: ReadonlyArray<string>, maxTokens: number) =>\n units.flatMap(unit =>\n countTokens(unit) <= maxTokens ? [unit] : splitOversizedUnit(unit, maxTokens)\n )\n\nconst buildChunkContents = (units: ReadonlyArray<string>, maxTokens: number) => {\n const chunks: string[] = []\n let current = ''\n let currentTokenCount = 0\n\n const pushCurrent = () => {\n const content = current.trim()\n if (content.length > 0) {\n chunks.push(content)\n }\n }\n\n for (const unit of units) {\n const unitTokenCount = countTokens(unit)\n\n if (currentTokenCount > 0 && currentTokenCount + unitTokenCount > maxTokens) {\n pushCurrent()\n current = unit\n currentTokenCount = unitTokenCount\n continue\n }\n\n current = `${current}${unit}`\n currentTokenCount += unitTokenCount\n }\n\n pushCurrent()\n return chunks\n}\n\nexport const chunkKnowledgeText = (input: ChunkKnowledgeDocumentInput, maxTokens: number) =>\n Effect.gen(function* () {\n if (!Number.isInteger(maxTokens) || maxTokens < 1) {\n return yield* Effect.fail(\n new KnowledgeChunkingError({ message: 'Chunk maxTokens must be a positive integer' })\n )\n }\n\n const sanitized = sanitizeText(input.content)\n if (sanitized.length === 0) {\n return yield* Effect.fail(new KnowledgeChunkingError({ message: 'Cannot chunk empty content' }))\n }\n\n const units = splitUnitsBySize(splitSentences(sanitized), maxTokens)\n const contents = buildChunkContents(units, maxTokens)\n\n if (contents.length === 0) {\n return yield* Effect.fail(new KnowledgeChunkingError({ message: 'No chunks produced' }))\n }\n\n return contents.map((content, position) => ({\n id: `${input.documentId}:chunk:${position}`,\n collectionId: input.collectionId,\n documentId: input.documentId,\n content,\n position,\n tokenCount: countTokens(content),\n metadata: input.metadata\n })) satisfies ReadonlyArray<KnowledgeChunk>\n })\n\nexport const makeDefaultKnowledgeChunker = (input: { readonly maxTokens: number }): KnowledgeChunkerApi => ({\n chunk: document => chunkKnowledgeText(document, document.maxTokens ?? input.maxTokens)\n})\n\nexport const DefaultKnowledgeChunkerLive = (input: { readonly maxTokens: number } = { maxTokens: 512 }) =>\n Layer.succeed(KnowledgeChunker, makeDefaultKnowledgeChunker(input))\n"],"mappings":"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"}
1
+ {"version":3,"file":"chunking.mjs","names":[],"sources":["../src/chunking.ts"],"sourcesContent":["import { Context, Effect, Layer } from 'effect'\nimport { countTokens, decode, encode } from 'gpt-tokenizer/encoding/o200k_base'\nimport type {\n KnowledgeChunk,\n KnowledgeDocumentId,\n KnowledgeMetadata,\n KnowledgeScopeId\n} from './documents.ts'\nimport { KnowledgeChunkingError } from './errors.ts'\n\nconst SENTENCE_PATTERN = /[^.!?]+[.!?]+(?:[\"')\\]]+)?\\s*|[^.!?]+$/g\n\nconst PARAGRAPH_BREAK_PATTERN = /(\\n{2,})/\n\nconst WORD_PATTERN = /\\S+\\s*/g\n\nexport type ChunkKnowledgeDocumentInput = {\n readonly scopeId: KnowledgeScopeId\n readonly documentId: KnowledgeDocumentId\n readonly content: string\n readonly maxTokens?: number\n readonly metadata?: KnowledgeMetadata\n}\n\nexport type KnowledgeChunkerApi = {\n readonly chunk: (\n input: ChunkKnowledgeDocumentInput\n ) => Effect.Effect<ReadonlyArray<KnowledgeChunk>, KnowledgeChunkingError>\n}\n\nexport class KnowledgeChunker extends Context.Service<KnowledgeChunker, KnowledgeChunkerApi>()(\n '@yolk-sdk/knowledge/KnowledgeChunker'\n) {}\n\nexport const countKnowledgeChunkTokens = (text: string) => countTokens(text)\n\nconst sanitizeText = (text: string) =>\n text\n .replace(/\\r\\n/g, '\\n')\n .replace(/[\\t ]+/g, ' ')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim()\n\nconst splitSentences = (text: string) =>\n text\n .split(PARAGRAPH_BREAK_PATTERN)\n .flatMap(part => {\n if (part.length === 0) {\n return []\n }\n\n if (/^\\n{2,}$/.test(part)) {\n return ['\\n\\n']\n }\n\n return part.match(SENTENCE_PATTERN) ?? [part]\n })\n .filter(unit => unit.length > 0)\n\nconst splitEncodedTokens = (text: string, maxTokens: number) => {\n const tokens = encode(text)\n\n return Array.from({ length: Math.ceil(tokens.length / maxTokens) }, (_, index) =>\n decode(tokens.slice(index * maxTokens, index * maxTokens + maxTokens)).trim()\n ).filter(chunk => chunk.length > 0)\n}\n\nconst splitOversizedUnit = (text: string, maxTokens: number) => {\n const words = text.match(WORD_PATTERN) ?? []\n const chunks: string[] = []\n let current = ''\n let currentTokenCount = 0\n\n for (const word of words) {\n const wordTokenCount = countTokens(word)\n\n if (wordTokenCount > maxTokens) {\n const currentChunk = current.trim()\n\n if (currentChunk.length > 0) {\n chunks.push(currentChunk)\n }\n\n chunks.push(...splitEncodedTokens(word, maxTokens))\n current = ''\n currentTokenCount = 0\n continue\n }\n\n if (currentTokenCount > 0 && currentTokenCount + wordTokenCount > maxTokens) {\n const currentChunk = current.trim()\n\n if (currentChunk.length > 0) {\n chunks.push(currentChunk)\n }\n\n current = word\n currentTokenCount = wordTokenCount\n continue\n }\n\n current = `${current}${word}`\n currentTokenCount += wordTokenCount\n }\n\n const finalChunk = current.trim()\n\n if (finalChunk.length > 0) {\n chunks.push(finalChunk)\n }\n\n return chunks\n}\n\nconst splitUnitsBySize = (units: ReadonlyArray<string>, maxTokens: number) =>\n units.flatMap(unit =>\n countTokens(unit) <= maxTokens ? [unit] : splitOversizedUnit(unit, maxTokens)\n )\n\nconst buildChunkContents = (units: ReadonlyArray<string>, maxTokens: number) => {\n const chunks: string[] = []\n let current = ''\n let currentTokenCount = 0\n\n const pushCurrent = () => {\n const content = current.trim()\n\n if (content.length > 0) {\n chunks.push(content)\n }\n }\n\n for (const unit of units) {\n const unitTokenCount = countTokens(unit)\n\n if (currentTokenCount > 0 && currentTokenCount + unitTokenCount > maxTokens) {\n pushCurrent()\n current = unit\n currentTokenCount = unitTokenCount\n continue\n }\n\n current = `${current}${unit}`\n currentTokenCount += unitTokenCount\n }\n\n pushCurrent()\n\n return chunks\n}\n\nexport const chunkKnowledgeText = (input: ChunkKnowledgeDocumentInput, maxTokens: number) =>\n Effect.gen(function* () {\n if (!Number.isInteger(maxTokens) || maxTokens < 1) {\n return yield* Effect.fail(\n new KnowledgeChunkingError({ message: 'Chunk maxTokens must be a positive integer' })\n )\n }\n\n const sanitized = sanitizeText(input.content)\n\n if (sanitized.length === 0) {\n return yield* Effect.fail(\n new KnowledgeChunkingError({ message: 'Cannot chunk empty content' })\n )\n }\n\n const units = splitUnitsBySize(splitSentences(sanitized), maxTokens)\n const contents = buildChunkContents(units, maxTokens)\n\n if (contents.length === 0) {\n return yield* Effect.fail(new KnowledgeChunkingError({ message: 'No chunks produced' }))\n }\n\n return contents.map((content, position) => ({\n id: `${input.documentId}:chunk:${position}`,\n scopeId: input.scopeId,\n documentId: input.documentId,\n content,\n position,\n tokenCount: countTokens(content),\n metadata: input.metadata\n })) satisfies ReadonlyArray<KnowledgeChunk>\n })\n\nexport const makeDefaultKnowledgeChunker = (input: {\n readonly maxTokens: number\n}): KnowledgeChunkerApi => ({\n chunk: document => chunkKnowledgeText(document, document.maxTokens ?? input.maxTokens)\n})\n\nexport const DefaultKnowledgeChunkerLive = (\n input: { readonly maxTokens: number } = { maxTokens: 512 }\n) => Layer.succeed(KnowledgeChunker, makeDefaultKnowledgeChunker(input))\n"],"mappings":"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"}
@@ -1,16 +1,7 @@
1
- import { KnowledgeRecord } from "./records.mjs";
2
- import { KnowledgeRepresentation } from "./representations.mjs";
3
-
4
- //#region src/context.d.ts
5
- type KnowledgeContextItem = {
6
- readonly record: KnowledgeRecord;
7
- readonly representation?: KnowledgeRepresentation;
8
- };
9
- type BuildKnowledgeContextInput = {
10
- readonly items: ReadonlyArray<KnowledgeContextItem>;
1
+ import { KnowledgeDocument } from "./documents.mjs";
2
+ export type BuildKnowledgeContextInput = {
3
+ readonly documents: ReadonlyArray<KnowledgeDocument>;
11
4
  readonly maxCharacters: number;
12
5
  };
13
- declare const buildKnowledgeContext: (input: BuildKnowledgeContextInput) => string;
14
- //#endregion
15
- export { BuildKnowledgeContextInput, KnowledgeContextItem, buildKnowledgeContext };
6
+ export declare const buildKnowledgeContext: (input: BuildKnowledgeContextInput) => string;
16
7
  //# sourceMappingURL=context.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.mts","names":[],"sources":["../src/context.ts"],"mappings":";;;;KAIY,oBAAA;EAAA,SACD,MAAA,EAAQ,eAAA;EAAA,SACR,cAAA,GAAiB,uBAAuB;AAAA;AAAA,KAGvC,0BAAA;EAAA,SACD,KAAA,EAAO,aAAa,CAAC,oBAAA;EAAA,SACrB,aAAA;AAAA;AAAA,cAeE,qBAAA,GAAyB,KAAiC,EAA1B,0BAA0B"}
1
+ {"version":3,"file":"context.d.mts","names":[],"sources":["../src/context.ts"],"mappings":";YAGY;WACD,WAAW,cAAc;WACzB;;qBAuBE,wBAAqB,OAAW"}
package/dist/context.mjs CHANGED
@@ -1,25 +1,29 @@
1
1
  import { Array } from "effect";
2
- //#region src/context.ts
2
+ // src/context.ts
3
3
  const truncationMarker = "\n\n[truncated: pinned knowledge exceeded context budget]";
4
- const recordHeader = (record) => `## ${record.title}\nrole: ${record.role}\nstatus: ${record.status}\ncontext: ${record.contextPolicy}`;
5
- const itemBody = (item) => {
6
- const representationText = item.representation?.summary ?? item.representation?.contentText;
7
- return [
8
- recordHeader(item.record),
9
- item.record.summary,
10
- representationText
11
- ].filter((section) => section !== void 0 && section.trim().length > 0).join("\n");
12
- };
4
+ const documentHeader = (document) => [
5
+ `## ${document.title}`,
6
+ `slug: ${document.slug}`,
7
+ `purpose: ${document.purpose}`,
8
+ `origin: ${document.origin}`,
9
+ `status: ${document.status}`,
10
+ `availability: ${document.availability}`,
11
+ document.reviewedAt === void 0 ? void 0 : `reviewed_at: ${document.reviewedAt.toString()}`
12
+ ].filter((line) => line !== void 0 && line.trim().length > 0).join("\n");
13
+ const documentBody = (document) => [
14
+ documentHeader(document),
15
+ document.summary,
16
+ document.content
17
+ ].filter((section) => section !== void 0 && section.trim().length > 0).join("\n");
13
18
  const buildKnowledgeContext = (input) => {
14
- const sections = Array.map(input.items, itemBody).filter((section) => section.trim().length > 0);
15
- const header = "# Pinned knowledge\nUse this durable user knowledge as high-priority context. Cite knowledge records when relevant.";
19
+ const sections = Array.map(input.documents, documentBody).filter((section) => section.trim().length > 0);
20
+ const header = "# Pinned knowledge\nUse this durable knowledge as high-priority context.";
16
21
  const body = sections.join("\n\n");
17
22
  const context = body.length === 0 ? "" : `${header}\n\n${body}`;
18
23
  if (context.length <= input.maxCharacters) return context;
19
24
  if (input.maxCharacters <= 55) return context.slice(0, input.maxCharacters).trimEnd();
20
25
  return `${context.slice(0, input.maxCharacters - 55).trimEnd()}${truncationMarker}`;
21
26
  };
22
- //#endregion
23
27
  export { buildKnowledgeContext };
24
28
 
25
29
  //# sourceMappingURL=context.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.mjs","names":["Arr"],"sources":["../src/context.ts"],"sourcesContent":["import { Array as Arr } from 'effect'\nimport type { KnowledgeRecord } from './records.ts'\nimport type { KnowledgeRepresentation } from './representations.ts'\n\nexport type KnowledgeContextItem = {\n readonly record: KnowledgeRecord\n readonly representation?: KnowledgeRepresentation\n}\n\nexport type BuildKnowledgeContextInput = {\n readonly items: ReadonlyArray<KnowledgeContextItem>\n readonly maxCharacters: number\n}\n\nconst truncationMarker = '\\n\\n[truncated: pinned knowledge exceeded context budget]'\n\nconst recordHeader = (record: KnowledgeRecord) =>\n `## ${record.title}\\nrole: ${record.role}\\nstatus: ${record.status}\\ncontext: ${record.contextPolicy}`\n\nconst itemBody = (item: KnowledgeContextItem) => {\n const representationText = item.representation?.summary ?? item.representation?.contentText\n return [recordHeader(item.record), item.record.summary, representationText]\n .filter(section => section !== undefined && section.trim().length > 0)\n .join('\\n')\n}\n\nexport const buildKnowledgeContext = (input: BuildKnowledgeContextInput) => {\n const sections = Arr.map(input.items, itemBody).filter(section => section.trim().length > 0)\n const header = '# Pinned knowledge\\nUse this durable user knowledge as high-priority context. Cite knowledge records when relevant.'\n const body = sections.join('\\n\\n')\n const context = body.length === 0 ? '' : `${header}\\n\\n${body}`\n\n if (context.length <= input.maxCharacters) {\n return context\n }\n\n if (input.maxCharacters <= truncationMarker.length) {\n return context.slice(0, input.maxCharacters).trimEnd()\n }\n\n return `${context.slice(0, input.maxCharacters - truncationMarker.length).trimEnd()}${truncationMarker}`\n}\n"],"mappings":";;AAcA,MAAM,mBAAmB;AAEzB,MAAM,gBAAgB,WACpB,MAAM,OAAO,MAAM,UAAU,OAAO,KAAK,YAAY,OAAO,OAAO,aAAa,OAAO;AAEzF,MAAM,YAAY,SAA+B;CAC/C,MAAM,qBAAqB,KAAK,gBAAgB,WAAW,KAAK,gBAAgB;CAChF,OAAO;EAAC,aAAa,KAAK,MAAM;EAAG,KAAK,OAAO;EAAS;CAAkB,EACvE,QAAO,YAAW,YAAY,KAAA,KAAa,QAAQ,KAAK,EAAE,SAAS,CAAC,EACpE,KAAK,IAAI;AACd;AAEA,MAAa,yBAAyB,UAAsC;CAC1E,MAAM,WAAWA,MAAI,IAAI,MAAM,OAAO,QAAQ,EAAE,QAAO,YAAW,QAAQ,KAAK,EAAE,SAAS,CAAC;CAC3F,MAAM,SAAS;CACf,MAAM,OAAO,SAAS,KAAK,MAAM;CACjC,MAAM,UAAU,KAAK,WAAW,IAAI,KAAK,GAAG,OAAO,MAAM;CAEzD,IAAI,QAAQ,UAAU,MAAM,eAC1B,OAAO;CAGT,IAAI,MAAM,iBAAiB,IACzB,OAAO,QAAQ,MAAM,GAAG,MAAM,aAAa,EAAE,QAAQ;CAGvD,OAAO,GAAG,QAAQ,MAAM,GAAG,MAAM,gBAAgB,EAAuB,EAAE,QAAQ,IAAI;AACxF"}
1
+ {"version":3,"file":"context.mjs","names":["Arr"],"sources":["../src/context.ts"],"sourcesContent":["import { Array as Arr } from 'effect'\nimport type { KnowledgeDocument } from './documents.ts'\n\nexport type BuildKnowledgeContextInput = {\n readonly documents: ReadonlyArray<KnowledgeDocument>\n readonly maxCharacters: number\n}\n\nconst truncationMarker = '\\n\\n[truncated: pinned knowledge exceeded context budget]'\n\nconst documentHeader = (document: KnowledgeDocument) =>\n [\n `## ${document.title}`,\n `slug: ${document.slug}`,\n `purpose: ${document.purpose}`,\n `origin: ${document.origin}`,\n `status: ${document.status}`,\n `availability: ${document.availability}`,\n document.reviewedAt === undefined ? undefined : `reviewed_at: ${document.reviewedAt.toString()}`\n ]\n .filter(line => line !== undefined && line.trim().length > 0)\n .join('\\n')\n\nconst documentBody = (document: KnowledgeDocument) =>\n [documentHeader(document), document.summary, document.content]\n .filter(section => section !== undefined && section.trim().length > 0)\n .join('\\n')\n\nexport const buildKnowledgeContext = (input: BuildKnowledgeContextInput) => {\n const sections = Arr.map(input.documents, documentBody).filter(\n section => section.trim().length > 0\n )\n\n const header = '# Pinned knowledge\\nUse this durable knowledge as high-priority context.'\n const body = sections.join('\\n\\n')\n const context = body.length === 0 ? '' : `${header}\\n\\n${body}`\n\n if (context.length <= input.maxCharacters) {\n return context\n }\n\n if (input.maxCharacters <= truncationMarker.length) {\n return context.slice(0, input.maxCharacters).trimEnd()\n }\n\n return `${context.slice(0, input.maxCharacters - truncationMarker.length).trimEnd()}${truncationMarker}`\n}\n"],"mappings":";;AAQA,MAAM,mBAAmB;AAEzB,MAAM,kBAAkB,aACtB;CACE,MAAM,SAAS;CACf,SAAS,SAAS;CAClB,YAAY,SAAS;CACrB,WAAW,SAAS;CACpB,WAAW,SAAS;CACpB,iBAAiB,SAAS;CAC1B,SAAS,eAAe,KAAA,IAAY,KAAA,IAAY,gBAAgB,SAAS,WAAW,SAAS;AAC/F,CAAC,CACE,QAAO,SAAQ,SAAS,KAAA,KAAa,KAAK,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAC5D,KAAK,IAAI;AAEd,MAAM,gBAAgB,aACpB;CAAC,eAAe,QAAQ;CAAG,SAAS;CAAS,SAAS;AAAO,CAAC,CAC3D,QAAO,YAAW,YAAY,KAAA,KAAa,QAAQ,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CACrE,KAAK,IAAI;AAEd,MAAa,yBAAyB,UAAsC;CAC1E,MAAM,WAAWA,MAAI,IAAI,MAAM,WAAW,YAAY,CAAC,CAAC,QACtD,YAAW,QAAQ,KAAK,CAAC,CAAC,SAAS,CACrC;CAEA,MAAM,SAAS;CACf,MAAM,OAAO,SAAS,KAAK,MAAM;CACjC,MAAM,UAAU,KAAK,WAAW,IAAI,KAAK,GAAG,OAAO,MAAM;CAEzD,IAAI,QAAQ,UAAU,MAAM,eAC1B,OAAO;CAGT,IAAI,MAAM,iBAAiB,IACzB,OAAO,QAAQ,MAAM,GAAG,MAAM,aAAa,CAAC,CAAC,QAAQ;CAGvD,OAAO,GAAG,QAAQ,MAAM,GAAG,MAAM,gBAAgB,EAAuB,CAAC,CAAC,QAAQ,IAAI;AACxF"}