@noetic-tools/core 0.0.1 → 0.1.1
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 +31 -11
- package/dist/adapters/in-memory-fs-adapter.d.ts +1 -1
- package/dist/adapters/in-memory-fs-adapter.js +1 -1
- package/dist/adapters/in-memory-shell-adapter.d.ts +1 -1
- package/dist/adapters/in-memory-subprocess/manifest-persistence.d.ts +8 -0
- package/dist/adapters/in-memory-subprocess/manifest-persistence.js +56 -0
- package/dist/adapters/in-memory-subprocess/metadata.d.ts +12 -0
- package/dist/adapters/in-memory-subprocess/metadata.js +58 -0
- package/dist/adapters/in-memory-subprocess/step-completion.d.ts +3 -0
- package/dist/adapters/in-memory-subprocess/step-completion.js +86 -0
- package/dist/adapters/in-memory-subprocess/types.d.ts +88 -0
- package/dist/adapters/in-memory-subprocess/types.js +2 -0
- package/dist/adapters/in-memory-subprocess-adapter.d.ts +12 -4
- package/dist/adapters/in-memory-subprocess-adapter.js +164 -55
- package/dist/adapters/openrouter.d.ts +16 -7
- package/dist/adapters/openrouter.js +68 -7
- package/dist/builders/channel-builder.d.ts +1 -1
- package/dist/builders/control-flow-builders.d.ts +3 -3
- package/dist/builders/control-flow-builders.js +9 -4
- package/dist/builders/every.d.ts +3 -3
- package/dist/builders/every.js +5 -2
- package/dist/builders/layer-provides-builders.d.ts +1 -32
- package/dist/builders/layer-provides-builders.js +1 -33
- package/dist/builders/loop-builder.d.ts +2 -2
- package/dist/builders/loop-builder.js +5 -2
- package/dist/builders/memory-builder.d.ts +1 -1
- package/dist/builders/memory-builder.js +1 -1
- package/dist/builders/provide-builder.d.ts +2 -2
- package/dist/builders/provide-builder.js +5 -2
- package/dist/builders/spawn-builder.d.ts +22 -9
- package/dist/builders/spawn-builder.js +17 -3
- package/dist/builders/step-builders.d.ts +51 -30
- package/dist/builders/step-builders.js +31 -12
- package/dist/builders/tool-builder.d.ts +7 -3
- package/dist/builders/tool-builder.js +3 -1
- package/dist/builders/workflow-hydrator.d.ts +38 -0
- package/dist/builders/workflow-hydrator.js +336 -0
- package/dist/conditions/conditions.d.ts +4 -4
- package/dist/conditions/conditions.js +2 -2
- package/dist/errors/noetic-error.d.ts +1 -1
- package/dist/errors/noetic-error.js +2 -0
- package/dist/{runtime → harness}/agent-harness.d.ts +65 -45
- package/dist/harness/agent-harness.js +576 -0
- package/dist/harness/deps/adapters.d.ts +4 -0
- package/dist/harness/deps/adapters.js +4 -0
- package/dist/harness/deps/interpreter.d.ts +5 -0
- package/dist/harness/deps/interpreter.js +4 -0
- package/dist/harness/deps/memory.d.ts +5 -0
- package/dist/harness/deps/memory.js +4 -0
- package/dist/harness/deps/runtime.d.ts +10 -0
- package/dist/harness/deps/runtime.js +7 -0
- package/dist/harness/deps/types.d.ts +17 -0
- package/dist/harness/deps/types.js +1 -0
- package/dist/harness/model-call.d.ts +50 -0
- package/dist/harness/model-call.js +694 -0
- package/dist/harness/model-schema.d.ts +19 -0
- package/dist/harness/model-schema.js +46 -0
- package/dist/harness/step-bootstrap.d.ts +25 -0
- package/dist/harness/step-bootstrap.js +170 -0
- package/dist/index.d.ts +114 -76
- package/dist/index.js +74 -50
- package/dist/internal-test.d.ts +4 -4
- package/dist/internal-test.js +4 -4
- package/dist/interpreter/action-deps.d.ts +12 -0
- package/dist/interpreter/action-deps.js +10 -0
- package/dist/interpreter/action-types.d.ts +8 -0
- package/dist/interpreter/action-types.js +1 -0
- package/dist/interpreter/collect-tools.d.ts +2 -2
- package/dist/interpreter/collect-tools.js +6 -2
- package/dist/interpreter/execute-action.d.ts +22 -0
- package/dist/interpreter/execute-action.js +527 -0
- package/dist/interpreter/{execute-every.d.ts → execute-control.d.ts} +8 -2
- package/dist/interpreter/execute-control.js +530 -0
- package/dist/interpreter/execute.d.ts +16 -3
- package/dist/interpreter/execute.js +154 -51
- package/dist/interpreter/message-helpers.d.ts +1 -9
- package/dist/interpreter/message-helpers.js +1 -42
- package/dist/interpreter/step-dispatcher.d.ts +61 -0
- package/dist/interpreter/step-dispatcher.js +67 -0
- package/dist/interpreter/typeguards.d.ts +8 -15
- package/dist/interpreter/typeguards.js +4 -21
- package/dist/memory/budget.d.ts +2 -2
- package/dist/memory/budget.js +1 -1
- package/dist/{runtime → memory}/exec-context-factory.d.ts +2 -2
- package/dist/{runtime → memory}/exec-context-factory.js +1 -1
- package/dist/memory/flow-schema.d.ts +52 -0
- package/dist/memory/flow-schema.js +102 -0
- package/dist/memory/function-call-utils.d.ts +1 -1
- package/dist/memory/function-call-utils.js +4 -2
- package/dist/memory/layer-api.d.ts +4 -4
- package/dist/memory/layer-api.js +2 -2
- package/dist/memory/layer-lifecycle.d.ts +6 -6
- package/dist/memory/layer-lifecycle.js +6 -6
- package/dist/memory/layer-provides.d.ts +32 -0
- package/dist/memory/layer-provides.js +33 -0
- package/dist/memory/layer-usage.d.ts +4 -3
- package/dist/memory/layer-usage.js +9 -3
- package/dist/memory/layers/durable-task-state.d.ts +8 -8
- package/dist/memory/layers/durable-task-state.js +2 -2
- package/dist/memory/layers/file-reference.d.ts +1 -1
- package/dist/memory/layers/file-reference.js +303 -247
- package/dist/memory/layers/history-window.d.ts +1 -1
- package/dist/memory/layers/history-window.js +4 -4
- package/dist/memory/layers/observational-memory.d.ts +5 -5
- package/dist/memory/layers/observational-memory.js +2 -3
- package/dist/memory/layers/plan.d.ts +2 -2
- package/dist/memory/layers/plan.js +15 -10
- package/dist/memory/layers/static-content.d.ts +2 -2
- package/dist/memory/layers/static-content.js +1 -1
- package/dist/memory/layers/steering.d.ts +7 -7
- package/dist/memory/layers/steering.js +5 -5
- package/dist/memory/layers/tool-memory-layer.d.ts +2 -2
- package/dist/memory/layers/tool-memory-layer.js +1 -1
- package/dist/memory/layers/working-memory.d.ts +7 -7
- package/dist/memory/layers/working-memory.js +4 -4
- package/dist/memory/projector.d.ts +2 -2
- package/dist/memory/scope.d.ts +1 -1
- package/dist/memory/strip-unresolved.d.ts +1 -1
- package/dist/observability/span-impl.d.ts +1 -1
- package/dist/observability/trace-exporter.d.ts +2 -2
- package/dist/observability/trace-exporter.js +1 -1
- package/dist/patterns/dynamic-workflow.d.ts +55 -0
- package/dist/patterns/dynamic-workflow.js +194 -0
- package/dist/patterns/flow.d.ts +2 -52
- package/dist/patterns/flow.js +1 -103
- package/dist/patterns/interview.d.ts +2 -2
- package/dist/patterns/interview.js +5 -5
- package/dist/patterns/plans.d.ts +6 -6
- package/dist/patterns/plans.js +4 -4
- package/dist/patterns/ralph-wiggum.d.ts +4 -4
- package/dist/patterns/ralph-wiggum.js +5 -5
- package/dist/patterns/react.d.ts +3 -3
- package/dist/patterns/react.js +5 -5
- package/dist/portable/adapters.d.ts +6 -0
- package/dist/portable/adapters.js +6 -0
- package/dist/portable/ask-user.d.ts +4 -0
- package/dist/portable/ask-user.js +2 -0
- package/dist/portable/builders.d.ts +12 -0
- package/dist/portable/builders.js +12 -0
- package/dist/portable/memory-layers.d.ts +12 -0
- package/dist/portable/memory-layers.js +12 -0
- package/dist/portable/runtime.d.ts +4 -0
- package/dist/portable/runtime.js +4 -0
- package/dist/portable/until.d.ts +4 -0
- package/dist/portable/until.js +4 -0
- package/dist/portable.d.ts +8 -26
- package/dist/portable.js +8 -34
- package/dist/runtime/broadcaster-utils.d.ts +7 -3
- package/dist/runtime/broadcaster-utils.js +11 -6
- package/dist/runtime/channel-store.d.ts +1 -1
- package/dist/runtime/channel-store.js +2 -2
- package/dist/runtime/context-deps.d.ts +4 -0
- package/dist/runtime/context-deps.js +2 -0
- package/dist/runtime/context-impl.d.ts +42 -12
- package/dist/runtime/context-impl.js +52 -5
- package/dist/runtime/context-type-deps.d.ts +14 -0
- package/dist/runtime/context-type-deps.js +1 -0
- package/dist/runtime/cwd-helpers.d.ts +1 -1
- package/dist/runtime/detached-handle.d.ts +52 -4
- package/dist/runtime/detached-handle.js +218 -14
- package/dist/runtime/durable/checkpoint-store.d.ts +38 -0
- package/dist/runtime/durable/checkpoint-store.js +101 -0
- package/dist/runtime/durable/detached-signal.d.ts +37 -0
- package/dist/runtime/durable/detached-signal.js +52 -0
- package/dist/runtime/durable/harness-checkpoints.d.ts +51 -0
- package/dist/runtime/durable/harness-checkpoints.js +104 -0
- package/dist/runtime/durable/index.d.ts +10 -0
- package/dist/runtime/durable/index.js +5 -0
- package/dist/runtime/durable/runnable-loop.d.ts +100 -0
- package/dist/runtime/durable/runnable-loop.js +90 -0
- package/dist/runtime/durable/session-seed.d.ts +28 -0
- package/dist/runtime/durable/session-seed.js +27 -0
- package/dist/runtime/durable/stall-nudge.d.ts +82 -0
- package/dist/runtime/durable/stall-nudge.js +87 -0
- package/dist/runtime/event-broadcaster.d.ts +1 -1
- package/dist/runtime/in-memory-storage.d.ts +1 -1
- package/dist/runtime/in-memory-storage.js +1 -1
- package/dist/runtime/item-log-impl.d.ts +3 -3
- package/dist/runtime/item-log-impl.js +1 -1
- package/dist/runtime/message-queue.d.ts +2 -2
- package/dist/runtime/session-runner.d.ts +7 -7
- package/dist/runtime/session-runner.js +3 -3
- package/dist/runtime/session-streams.d.ts +3 -3
- package/dist/runtime/session-streams.js +1 -1
- package/dist/runtime/step-registry.d.ts +42 -0
- package/dist/runtime/step-registry.js +77 -0
- package/dist/runtime/tool-memory.d.ts +3 -3
- package/dist/schemas/item.d.ts +1 -1
- package/dist/schemas/workflow.d.ts +139 -0
- package/dist/schemas/workflow.js +232 -0
- package/dist/types/ask-user-types.d.ts +57 -0
- package/dist/types/ask-user-types.js +74 -0
- package/dist/types/checkpoint.d.ts +98 -0
- package/dist/types/checkpoint.js +81 -0
- package/dist/types/common.d.ts +1 -50
- package/dist/types/context-parts/item-log.d.ts +6 -0
- package/dist/types/context-parts/item-log.js +1 -0
- package/dist/types/context-parts/layer-usage.d.ts +18 -0
- package/dist/types/context-parts/layer-usage.js +1 -0
- package/dist/types/context.d.ts +140 -31
- package/dist/types/error.d.ts +15 -0
- package/dist/types/harness-result.d.ts +2 -2
- package/dist/types/items.d.ts +18 -2
- package/dist/types/memory-context.d.ts +39 -0
- package/dist/types/memory-context.js +1 -0
- package/dist/types/memory.d.ts +38 -68
- package/dist/types/mutable-context.d.ts +3 -3
- package/dist/types/runtime.d.ts +14 -13
- package/dist/types/steering.d.ts +2 -2
- package/dist/types/step-registrar.d.ts +46 -0
- package/dist/types/step-registrar.js +56 -0
- package/dist/types/step.d.ts +34 -9
- package/dist/types/subprocess-adapter.d.ts +119 -3
- package/dist/types/subprocess-adapter.js +2 -0
- package/dist/types/tool-context.d.ts +6 -6
- package/dist/types/tool.d.ts +64 -0
- package/dist/types/tool.js +1 -0
- package/dist/unstable.d.ts +9 -9
- package/dist/unstable.js +7 -7
- package/dist/until/combinators.d.ts +1 -1
- package/dist/until/never.d.ts +1 -1
- package/dist/until/predicates.d.ts +13 -4
- package/dist/until/predicates.js +16 -2
- package/dist/util/message-helpers.d.ts +17 -0
- package/dist/util/message-helpers.js +64 -0
- package/package.json +6 -4
- package/dist/adapters/local-fs-adapter.d.ts +0 -3
- package/dist/adapters/local-fs-adapter.js +0 -43
- package/dist/adapters/local-shell-adapter.d.ts +0 -51
- package/dist/adapters/local-shell-adapter.js +0 -167
- package/dist/adapters/local-subprocess-adapter.d.ts +0 -16
- package/dist/adapters/local-subprocess-adapter.js +0 -187
- package/dist/conditions/index.d.ts +0 -3
- package/dist/conditions/index.js +0 -2
- package/dist/interpreter/execute-branch.d.ts +0 -3
- package/dist/interpreter/execute-branch.js +0 -10
- package/dist/interpreter/execute-every.js +0 -143
- package/dist/interpreter/execute-fork.d.ts +0 -3
- package/dist/interpreter/execute-fork.js +0 -215
- package/dist/interpreter/execute-llm.d.ts +0 -4
- package/dist/interpreter/execute-llm.js +0 -217
- package/dist/interpreter/execute-loop.d.ts +0 -3
- package/dist/interpreter/execute-loop.js +0 -171
- package/dist/interpreter/execute-provide.d.ts +0 -10
- package/dist/interpreter/execute-provide.js +0 -64
- package/dist/interpreter/execute-run.d.ts +0 -3
- package/dist/interpreter/execute-run.js +0 -39
- package/dist/interpreter/execute-spawn.d.ts +0 -11
- package/dist/interpreter/execute-spawn.js +0 -113
- package/dist/interpreter/execute-tool.d.ts +0 -5
- package/dist/interpreter/execute-tool.js +0 -81
- package/dist/runtime/agent-harness.js +0 -1170
- /package/dist/{interpreter → util}/framework-cast.d.ts +0 -0
- /package/dist/{interpreter → util}/framework-cast.js +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Slot } from '../../types/memory.js';
|
|
2
|
+
import { createMessage, estimateTokens } from '../../util/message-helpers.js';
|
|
3
3
|
/** Default max file size: 1MB */
|
|
4
4
|
const DEFAULT_MAX_FILE_SIZE = 1024 * 1024;
|
|
5
5
|
/** Default allowed extensions */
|
|
@@ -122,12 +122,20 @@ function simpleHash(content) {
|
|
|
122
122
|
// Include content length to reduce collision probability
|
|
123
123
|
return `${content.length}:${hash.toString(16)}`;
|
|
124
124
|
}
|
|
125
|
+
function isInputTextPart(value) {
|
|
126
|
+
return (typeof value === 'object' &&
|
|
127
|
+
value !== null &&
|
|
128
|
+
'type' in value &&
|
|
129
|
+
value.type === 'input_text' &&
|
|
130
|
+
'text' in value &&
|
|
131
|
+
typeof value.text === 'string');
|
|
132
|
+
}
|
|
125
133
|
function isInputMessage(item) {
|
|
126
134
|
return (item.type === 'message' &&
|
|
127
135
|
'role' in item &&
|
|
128
136
|
'content' in item &&
|
|
129
137
|
Array.isArray(item.content) &&
|
|
130
|
-
item.content.every(
|
|
138
|
+
item.content.every(isInputTextPart));
|
|
131
139
|
}
|
|
132
140
|
function extractTextFromItem(item) {
|
|
133
141
|
if (!isInputMessage(item)) {
|
|
@@ -264,6 +272,293 @@ Score:`;
|
|
|
264
272
|
return 50;
|
|
265
273
|
}
|
|
266
274
|
}
|
|
275
|
+
function createFileReferenceRuntime(opts) {
|
|
276
|
+
const baseDir = opts?.baseDir ?? currentWorkingDirectory();
|
|
277
|
+
const maxFileSize = opts?.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
278
|
+
const followSymlinks = opts?.followSymlinks ?? false;
|
|
279
|
+
const allowedExtensions = opts?.allowedExtensions ?? DEFAULT_ALLOWED_EXTENSIONS;
|
|
280
|
+
return {
|
|
281
|
+
baseDir,
|
|
282
|
+
slot: opts?.slot ?? Slot.RAG,
|
|
283
|
+
scoringModel: opts?.scoringModel ?? 'anthropic/claude-haiku-4-5-20251001',
|
|
284
|
+
readOpts: {
|
|
285
|
+
maxFileSize,
|
|
286
|
+
followSymlinks,
|
|
287
|
+
baseDir,
|
|
288
|
+
allowedExtensions,
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
async function initFileReferenceState(baseDir) {
|
|
293
|
+
return {
|
|
294
|
+
state: {
|
|
295
|
+
files: new Map(),
|
|
296
|
+
baseDir,
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
function absolutePathReference(ref) {
|
|
301
|
+
return {
|
|
302
|
+
absolutePath: ref,
|
|
303
|
+
referencePath: ref,
|
|
304
|
+
content: null,
|
|
305
|
+
priority: 0,
|
|
306
|
+
contentHash: '',
|
|
307
|
+
deleted: false,
|
|
308
|
+
tokenCount: 0,
|
|
309
|
+
error: 'ABSOLUTE_PATH: Only relative paths are allowed',
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
async function trackNewReference(args) {
|
|
313
|
+
if (isAbsolutePath(args.ref)) {
|
|
314
|
+
return absolutePathReference(args.ref);
|
|
315
|
+
}
|
|
316
|
+
const absolutePath = resolvePath(args.state.baseDir, args.ref);
|
|
317
|
+
const result = await readFileContent(absolutePath, args.readOpts, args.ctx.fs);
|
|
318
|
+
const priority = result.content
|
|
319
|
+
? await scoreFileRelevance({
|
|
320
|
+
filePath: args.ref,
|
|
321
|
+
fileContent: result.content,
|
|
322
|
+
userQuery: args.userQuery,
|
|
323
|
+
ctx: args.ctx,
|
|
324
|
+
model: args.scoringModel,
|
|
325
|
+
})
|
|
326
|
+
: 0;
|
|
327
|
+
return {
|
|
328
|
+
absolutePath,
|
|
329
|
+
referencePath: args.ref,
|
|
330
|
+
content: result.content,
|
|
331
|
+
priority,
|
|
332
|
+
contentHash: result.content ? simpleHash(result.content) : '',
|
|
333
|
+
deleted: result.deleted,
|
|
334
|
+
tokenCount: result.content ? estimateTokens(result.content) : 0,
|
|
335
|
+
error: result.error,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
async function addNewReferences(args) {
|
|
339
|
+
let hasChanges = false;
|
|
340
|
+
for (const ref of args.refs) {
|
|
341
|
+
if (args.files.has(ref)) {
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
args.files.set(ref, await trackNewReference({
|
|
345
|
+
...args,
|
|
346
|
+
ref,
|
|
347
|
+
}));
|
|
348
|
+
hasChanges = true;
|
|
349
|
+
}
|
|
350
|
+
return hasChanges;
|
|
351
|
+
}
|
|
352
|
+
function transformItemReferences(item, refs) {
|
|
353
|
+
if (refs.length === 0 || !isInputMessage(item)) {
|
|
354
|
+
return item;
|
|
355
|
+
}
|
|
356
|
+
const transformedContent = item.content.map((c) => ({
|
|
357
|
+
type: 'input_text',
|
|
358
|
+
text: transformReferencesToAnchors(c.text),
|
|
359
|
+
}));
|
|
360
|
+
return {
|
|
361
|
+
...item,
|
|
362
|
+
content: transformedContent,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
async function processAppendedItems(args) {
|
|
366
|
+
const transformedItems = [];
|
|
367
|
+
let hasChanges = false;
|
|
368
|
+
let userQuery = '';
|
|
369
|
+
for (const item of args.items) {
|
|
370
|
+
const text = extractTextFromItem(item);
|
|
371
|
+
if (!text) {
|
|
372
|
+
transformedItems.push(item);
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
if (item.type === 'message' && 'role' in item && item.role === 'user') {
|
|
376
|
+
userQuery = text;
|
|
377
|
+
}
|
|
378
|
+
const refs = extractFileReferences(text);
|
|
379
|
+
const added = await addNewReferences({
|
|
380
|
+
refs,
|
|
381
|
+
files: args.files,
|
|
382
|
+
state: args.state,
|
|
383
|
+
readOpts: args.readOpts,
|
|
384
|
+
ctx: args.ctx,
|
|
385
|
+
userQuery,
|
|
386
|
+
scoringModel: args.scoringModel,
|
|
387
|
+
});
|
|
388
|
+
hasChanges = hasChanges || added;
|
|
389
|
+
transformedItems.push(transformItemReferences(item, refs));
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
transformedItems,
|
|
393
|
+
hasChanges,
|
|
394
|
+
userQuery,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
async function refreshTrackedFile(args) {
|
|
398
|
+
if (args.tracked.error) {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
const result = await readFileContent(args.tracked.absolutePath, args.readOpts, args.ctx.fs);
|
|
402
|
+
if (result.deleted && !args.tracked.deleted) {
|
|
403
|
+
return {
|
|
404
|
+
...args.tracked,
|
|
405
|
+
content: null,
|
|
406
|
+
deleted: true,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
if (result.error && !args.tracked.error) {
|
|
410
|
+
return {
|
|
411
|
+
...args.tracked,
|
|
412
|
+
content: null,
|
|
413
|
+
error: result.error,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
if (result.deleted || !result.content) {
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
const newHash = simpleHash(result.content);
|
|
420
|
+
if (newHash === args.tracked.contentHash) {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
const priority = args.userQuery
|
|
424
|
+
? await scoreFileRelevance({
|
|
425
|
+
filePath: args.ref,
|
|
426
|
+
fileContent: result.content,
|
|
427
|
+
userQuery: args.userQuery,
|
|
428
|
+
ctx: args.ctx,
|
|
429
|
+
model: args.scoringModel,
|
|
430
|
+
})
|
|
431
|
+
: args.tracked.priority;
|
|
432
|
+
return {
|
|
433
|
+
...args.tracked,
|
|
434
|
+
content: result.content,
|
|
435
|
+
contentHash: newHash,
|
|
436
|
+
deleted: false,
|
|
437
|
+
tokenCount: estimateTokens(result.content),
|
|
438
|
+
priority,
|
|
439
|
+
error: undefined,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
async function refreshTrackedFiles(args) {
|
|
443
|
+
let hasChanges = false;
|
|
444
|
+
for (const [ref, tracked] of args.files) {
|
|
445
|
+
const next = await refreshTrackedFile({
|
|
446
|
+
...args,
|
|
447
|
+
ref,
|
|
448
|
+
tracked,
|
|
449
|
+
});
|
|
450
|
+
if (next === null) {
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
args.files.set(ref, next);
|
|
454
|
+
hasChanges = true;
|
|
455
|
+
}
|
|
456
|
+
return hasChanges;
|
|
457
|
+
}
|
|
458
|
+
async function onFileReferenceItemAppend(args, runtime) {
|
|
459
|
+
const newFiles = new Map(args.state.files);
|
|
460
|
+
const currentReadOpts = {
|
|
461
|
+
...runtime.readOpts,
|
|
462
|
+
baseDir: args.state.baseDir,
|
|
463
|
+
};
|
|
464
|
+
const processed = await processAppendedItems({
|
|
465
|
+
items: args.items,
|
|
466
|
+
files: newFiles,
|
|
467
|
+
state: args.state,
|
|
468
|
+
readOpts: currentReadOpts,
|
|
469
|
+
ctx: args.ctx,
|
|
470
|
+
scoringModel: runtime.scoringModel,
|
|
471
|
+
});
|
|
472
|
+
const refreshed = await refreshTrackedFiles({
|
|
473
|
+
files: newFiles,
|
|
474
|
+
readOpts: currentReadOpts,
|
|
475
|
+
ctx: args.ctx,
|
|
476
|
+
userQuery: processed.userQuery,
|
|
477
|
+
scoringModel: runtime.scoringModel,
|
|
478
|
+
});
|
|
479
|
+
return {
|
|
480
|
+
items: processed.transformedItems,
|
|
481
|
+
state: {
|
|
482
|
+
...args.state,
|
|
483
|
+
files: newFiles,
|
|
484
|
+
},
|
|
485
|
+
rerender: processed.hasChanges || refreshed,
|
|
486
|
+
timing: 'immediate',
|
|
487
|
+
scope: 'self',
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
function buildDeletedOrErrorBlock(file) {
|
|
491
|
+
if (file.deleted) {
|
|
492
|
+
return `## ${file.referencePath}\n\n[FILE DELETED: ${file.absolutePath}]`;
|
|
493
|
+
}
|
|
494
|
+
if (file.error) {
|
|
495
|
+
return `## ${file.referencePath}\n\n[ERROR: ${file.error}]`;
|
|
496
|
+
}
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
function truncateFileContent(file, remainingBudget) {
|
|
500
|
+
if (!file.content || file.tokenCount <= remainingBudget) {
|
|
501
|
+
return file.content ?? '';
|
|
502
|
+
}
|
|
503
|
+
const lines = file.content.split('\n');
|
|
504
|
+
const headLines = Math.floor(lines.length * 0.6);
|
|
505
|
+
const tailLines = Math.floor(lines.length * 0.3);
|
|
506
|
+
const head = lines.slice(0, headLines).join('\n');
|
|
507
|
+
const tail = lines.slice(-tailLines).join('\n');
|
|
508
|
+
return `${head}\n\n... [truncated ${lines.length - headLines - tailLines} lines] ...\n\n${tail}`;
|
|
509
|
+
}
|
|
510
|
+
function buildContentBlock(file, totalTokens, budget) {
|
|
511
|
+
const statusBlock = buildDeletedOrErrorBlock(file);
|
|
512
|
+
if (statusBlock !== null) {
|
|
513
|
+
return totalTokens + estimateTokens(statusBlock) <= budget ? statusBlock : null;
|
|
514
|
+
}
|
|
515
|
+
if (!file.content) {
|
|
516
|
+
return null;
|
|
517
|
+
}
|
|
518
|
+
const header = `## ${file.referencePath}`;
|
|
519
|
+
const headerTokens = estimateTokens(header);
|
|
520
|
+
if (totalTokens + headerTokens >= budget) {
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
const remainingBudget = budget - totalTokens - headerTokens - 10;
|
|
524
|
+
const contentToInclude = truncateFileContent(file, remainingBudget);
|
|
525
|
+
return `${header}\n\n\`\`\`\n${contentToInclude}\n\`\`\``;
|
|
526
|
+
}
|
|
527
|
+
async function recallFileReferences({ state, budget, }) {
|
|
528
|
+
if (state.files.size === 0) {
|
|
529
|
+
return {
|
|
530
|
+
items: [],
|
|
531
|
+
tokenCount: 0,
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
const sortedFiles = [
|
|
535
|
+
...state.files.values(),
|
|
536
|
+
].sort((a, b) => b.priority - a.priority);
|
|
537
|
+
const blocks = [];
|
|
538
|
+
let totalTokens = 0;
|
|
539
|
+
for (const file of sortedFiles) {
|
|
540
|
+
const block = buildContentBlock(file, totalTokens, budget);
|
|
541
|
+
if (block === null) {
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
const blockTokens = estimateTokens(block);
|
|
545
|
+
blocks.push(block);
|
|
546
|
+
totalTokens += blockTokens;
|
|
547
|
+
}
|
|
548
|
+
if (blocks.length === 0) {
|
|
549
|
+
return {
|
|
550
|
+
items: [],
|
|
551
|
+
tokenCount: 0,
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
const content = `# Referenced Files\n\n${blocks.join('\n\n')}`;
|
|
555
|
+
return {
|
|
556
|
+
items: [
|
|
557
|
+
createMessage(content, 'developer'),
|
|
558
|
+
],
|
|
559
|
+
tokenCount: estimateTokens(content),
|
|
560
|
+
};
|
|
561
|
+
}
|
|
267
562
|
//#endregion
|
|
268
563
|
//#region Layer Factory
|
|
269
564
|
/**
|
|
@@ -281,257 +576,18 @@ Score:`;
|
|
|
281
576
|
* @public
|
|
282
577
|
*/
|
|
283
578
|
export function fileReference(opts) {
|
|
284
|
-
const
|
|
285
|
-
const slot = opts?.slot ?? Slot.RAG;
|
|
286
|
-
const scoringModel = opts?.scoringModel ?? 'anthropic/claude-haiku-4-5-20251001';
|
|
287
|
-
const maxFileSize = opts?.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
288
|
-
const followSymlinks = opts?.followSymlinks ?? false;
|
|
289
|
-
const allowedExtensions = opts?.allowedExtensions ?? DEFAULT_ALLOWED_EXTENSIONS;
|
|
290
|
-
// Pre-compute read options for reuse
|
|
291
|
-
const readOpts = {
|
|
292
|
-
maxFileSize,
|
|
293
|
-
followSymlinks,
|
|
294
|
-
baseDir,
|
|
295
|
-
allowedExtensions,
|
|
296
|
-
};
|
|
579
|
+
const runtime = createFileReferenceRuntime(opts);
|
|
297
580
|
return {
|
|
298
581
|
id: 'file-reference',
|
|
299
582
|
name: 'File Reference',
|
|
300
|
-
slot,
|
|
583
|
+
slot: runtime.slot,
|
|
301
584
|
scope: 'thread',
|
|
302
585
|
budget: 'auto',
|
|
303
586
|
rerenderTiming: 'immediate',
|
|
304
587
|
hooks: {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
files: new Map(),
|
|
309
|
-
baseDir,
|
|
310
|
-
},
|
|
311
|
-
};
|
|
312
|
-
},
|
|
313
|
-
async onItemAppend({ items, ctx, state }) {
|
|
314
|
-
const newFiles = new Map(state.files);
|
|
315
|
-
let hasChanges = false;
|
|
316
|
-
let userQuery = '';
|
|
317
|
-
// Update readOpts with current state's baseDir
|
|
318
|
-
const currentReadOpts = {
|
|
319
|
-
...readOpts,
|
|
320
|
-
baseDir: state.baseDir,
|
|
321
|
-
};
|
|
322
|
-
// Process each item
|
|
323
|
-
const transformedItems = [];
|
|
324
|
-
for (const item of items) {
|
|
325
|
-
const text = extractTextFromItem(item);
|
|
326
|
-
if (!text) {
|
|
327
|
-
transformedItems.push(item);
|
|
328
|
-
continue;
|
|
329
|
-
}
|
|
330
|
-
// Extract user query for scoring
|
|
331
|
-
if (item.type === 'message' && 'role' in item && item.role === 'user') {
|
|
332
|
-
userQuery = text;
|
|
333
|
-
}
|
|
334
|
-
// Extract file references
|
|
335
|
-
const refs = extractFileReferences(text);
|
|
336
|
-
// Process new references
|
|
337
|
-
for (const ref of refs) {
|
|
338
|
-
if (!newFiles.has(ref)) {
|
|
339
|
-
// Security: Reject absolute paths - all paths must be relative to baseDir
|
|
340
|
-
if (isAbsolutePath(ref)) {
|
|
341
|
-
newFiles.set(ref, {
|
|
342
|
-
absolutePath: ref,
|
|
343
|
-
referencePath: ref,
|
|
344
|
-
content: null,
|
|
345
|
-
priority: 0,
|
|
346
|
-
contentHash: '',
|
|
347
|
-
deleted: false,
|
|
348
|
-
tokenCount: 0,
|
|
349
|
-
error: 'ABSOLUTE_PATH: Only relative paths are allowed',
|
|
350
|
-
});
|
|
351
|
-
hasChanges = true;
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
const absolutePath = resolvePath(state.baseDir, ref);
|
|
355
|
-
const result = await readFileContent(absolutePath, currentReadOpts, ctx.fs);
|
|
356
|
-
const priority = result.content
|
|
357
|
-
? await scoreFileRelevance({
|
|
358
|
-
filePath: ref,
|
|
359
|
-
fileContent: result.content,
|
|
360
|
-
userQuery,
|
|
361
|
-
ctx,
|
|
362
|
-
model: scoringModel,
|
|
363
|
-
})
|
|
364
|
-
: 0;
|
|
365
|
-
newFiles.set(ref, {
|
|
366
|
-
absolutePath,
|
|
367
|
-
referencePath: ref,
|
|
368
|
-
content: result.content,
|
|
369
|
-
priority,
|
|
370
|
-
contentHash: result.content ? simpleHash(result.content) : '',
|
|
371
|
-
deleted: result.deleted,
|
|
372
|
-
tokenCount: result.content ? estimateTokens(result.content) : 0,
|
|
373
|
-
error: result.error,
|
|
374
|
-
});
|
|
375
|
-
hasChanges = true;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
// Transform references to anchor links
|
|
379
|
-
if (refs.length > 0 && isInputMessage(item)) {
|
|
380
|
-
const transformedContent = item.content.map((c) => {
|
|
381
|
-
const part = {
|
|
382
|
-
type: 'input_text',
|
|
383
|
-
text: transformReferencesToAnchors(c.text),
|
|
384
|
-
};
|
|
385
|
-
return part;
|
|
386
|
-
});
|
|
387
|
-
const transformedItem = {
|
|
388
|
-
...item,
|
|
389
|
-
content: transformedContent,
|
|
390
|
-
};
|
|
391
|
-
transformedItems.push(transformedItem);
|
|
392
|
-
}
|
|
393
|
-
else {
|
|
394
|
-
transformedItems.push(item);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
// Check existing files for changes
|
|
398
|
-
for (const [ref, tracked] of newFiles) {
|
|
399
|
-
// Skip files with errors - they won't change
|
|
400
|
-
if (tracked.error) {
|
|
401
|
-
continue;
|
|
402
|
-
}
|
|
403
|
-
const result = await readFileContent(tracked.absolutePath, currentReadOpts, ctx.fs);
|
|
404
|
-
if (result.deleted && !tracked.deleted) {
|
|
405
|
-
// File was deleted
|
|
406
|
-
newFiles.set(ref, {
|
|
407
|
-
...tracked,
|
|
408
|
-
content: null,
|
|
409
|
-
deleted: true,
|
|
410
|
-
});
|
|
411
|
-
hasChanges = true;
|
|
412
|
-
}
|
|
413
|
-
else if (result.error && !tracked.error) {
|
|
414
|
-
// File now has error (e.g., permission changed)
|
|
415
|
-
newFiles.set(ref, {
|
|
416
|
-
...tracked,
|
|
417
|
-
content: null,
|
|
418
|
-
error: result.error,
|
|
419
|
-
});
|
|
420
|
-
hasChanges = true;
|
|
421
|
-
}
|
|
422
|
-
else if (!result.deleted && result.content) {
|
|
423
|
-
const newHash = simpleHash(result.content);
|
|
424
|
-
if (newHash !== tracked.contentHash) {
|
|
425
|
-
// File content changed
|
|
426
|
-
const priority = userQuery
|
|
427
|
-
? await scoreFileRelevance({
|
|
428
|
-
filePath: ref,
|
|
429
|
-
fileContent: result.content,
|
|
430
|
-
userQuery,
|
|
431
|
-
ctx,
|
|
432
|
-
model: scoringModel,
|
|
433
|
-
})
|
|
434
|
-
: tracked.priority;
|
|
435
|
-
newFiles.set(ref, {
|
|
436
|
-
...tracked,
|
|
437
|
-
content: result.content,
|
|
438
|
-
contentHash: newHash,
|
|
439
|
-
deleted: false,
|
|
440
|
-
tokenCount: estimateTokens(result.content),
|
|
441
|
-
priority,
|
|
442
|
-
error: undefined,
|
|
443
|
-
});
|
|
444
|
-
hasChanges = true;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
return {
|
|
449
|
-
items: transformedItems,
|
|
450
|
-
state: {
|
|
451
|
-
...state,
|
|
452
|
-
files: newFiles,
|
|
453
|
-
},
|
|
454
|
-
rerender: hasChanges,
|
|
455
|
-
timing: 'immediate',
|
|
456
|
-
scope: 'self',
|
|
457
|
-
};
|
|
458
|
-
},
|
|
459
|
-
async recall({ state, budget }) {
|
|
460
|
-
if (state.files.size === 0) {
|
|
461
|
-
return {
|
|
462
|
-
items: [],
|
|
463
|
-
tokenCount: 0,
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
// Sort files by priority (highest first)
|
|
467
|
-
const sortedFiles = [
|
|
468
|
-
...state.files.values(),
|
|
469
|
-
].sort((a, b) => b.priority - a.priority);
|
|
470
|
-
// Build content blocks within budget
|
|
471
|
-
const blocks = [];
|
|
472
|
-
let totalTokens = 0;
|
|
473
|
-
for (const file of sortedFiles) {
|
|
474
|
-
// Handle deleted files
|
|
475
|
-
if (file.deleted) {
|
|
476
|
-
const block = `## ${file.referencePath}\n\n[FILE DELETED: ${file.absolutePath}]`;
|
|
477
|
-
const tokens = estimateTokens(block);
|
|
478
|
-
if (totalTokens + tokens <= budget) {
|
|
479
|
-
blocks.push(block);
|
|
480
|
-
totalTokens += tokens;
|
|
481
|
-
}
|
|
482
|
-
continue;
|
|
483
|
-
}
|
|
484
|
-
// Handle files with errors (security, size, permission)
|
|
485
|
-
if (file.error) {
|
|
486
|
-
const block = `## ${file.referencePath}\n\n[ERROR: ${file.error}]`;
|
|
487
|
-
const tokens = estimateTokens(block);
|
|
488
|
-
if (totalTokens + tokens <= budget) {
|
|
489
|
-
blocks.push(block);
|
|
490
|
-
totalTokens += tokens;
|
|
491
|
-
}
|
|
492
|
-
continue;
|
|
493
|
-
}
|
|
494
|
-
if (!file.content) {
|
|
495
|
-
continue;
|
|
496
|
-
}
|
|
497
|
-
const header = `## ${file.referencePath}`;
|
|
498
|
-
const headerTokens = estimateTokens(header);
|
|
499
|
-
if (totalTokens + headerTokens >= budget) {
|
|
500
|
-
// Can't fit even the header
|
|
501
|
-
break;
|
|
502
|
-
}
|
|
503
|
-
const remainingBudget = budget - totalTokens - headerTokens - 10; // Buffer for formatting
|
|
504
|
-
let contentToInclude = file.content;
|
|
505
|
-
if (file.tokenCount > remainingBudget) {
|
|
506
|
-
// Truncate content - show head + tail
|
|
507
|
-
const lines = file.content.split('\n');
|
|
508
|
-
const headLines = Math.floor(lines.length * 0.6);
|
|
509
|
-
const tailLines = Math.floor(lines.length * 0.3);
|
|
510
|
-
const head = lines.slice(0, headLines).join('\n');
|
|
511
|
-
const tail = lines.slice(-tailLines).join('\n');
|
|
512
|
-
contentToInclude = `${head}\n\n... [truncated ${lines.length - headLines - tailLines} lines] ...\n\n${tail}`;
|
|
513
|
-
}
|
|
514
|
-
const block = `${header}\n\n\`\`\`\n${contentToInclude}\n\`\`\``;
|
|
515
|
-
const blockTokens = estimateTokens(block);
|
|
516
|
-
if (totalTokens + blockTokens <= budget) {
|
|
517
|
-
blocks.push(block);
|
|
518
|
-
totalTokens += blockTokens;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
if (blocks.length === 0) {
|
|
522
|
-
return {
|
|
523
|
-
items: [],
|
|
524
|
-
tokenCount: 0,
|
|
525
|
-
};
|
|
526
|
-
}
|
|
527
|
-
const content = `# Referenced Files\n\n${blocks.join('\n\n')}`;
|
|
528
|
-
return {
|
|
529
|
-
items: [
|
|
530
|
-
createMessage(content, 'developer'),
|
|
531
|
-
],
|
|
532
|
-
tokenCount: estimateTokens(content),
|
|
533
|
-
};
|
|
534
|
-
},
|
|
588
|
+
init: () => initFileReferenceState(runtime.baseDir),
|
|
589
|
+
onItemAppend: (args) => onFileReferenceItemAppend(args, runtime),
|
|
590
|
+
recall: recallFileReferences,
|
|
535
591
|
},
|
|
536
592
|
};
|
|
537
593
|
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* 3. Drop any orphan `function_call` / `function_call_output` left at the
|
|
13
13
|
* slice boundary via `stripUnresolvedToolCalls`.
|
|
14
14
|
*/
|
|
15
|
-
import type { MemoryLayer } from '../../types/memory';
|
|
15
|
+
import type { MemoryLayer } from '../../types/memory.js';
|
|
16
16
|
/** @public Configuration for the {@link historyWindow} layer. */
|
|
17
17
|
export interface HistoryWindowConfig {
|
|
18
18
|
/** Cap on the number of trailing items projected to the LLM. Defaults to 40. */
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
* 3. Drop any orphan `function_call` / `function_call_output` left at the
|
|
13
13
|
* slice boundary via `stripUnresolvedToolCalls`.
|
|
14
14
|
*/
|
|
15
|
-
import { NoeticConfigError } from '../../errors/noetic-config-error';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { stripUnresolvedToolCalls } from '../strip-unresolved';
|
|
15
|
+
import { NoeticConfigError } from '../../errors/noetic-config-error.js';
|
|
16
|
+
import { Slot } from '../../types/memory.js';
|
|
17
|
+
import { isAssistantMessage, isUserMessage } from '../../util/message-helpers.js';
|
|
18
|
+
import { stripUnresolvedToolCalls } from '../strip-unresolved.js';
|
|
19
19
|
//#region Constants
|
|
20
20
|
const DEFAULT_MAX_ITEMS = 40;
|
|
21
21
|
const MIN_MAX_ITEMS = 2;
|
|
@@ -31,14 +31,14 @@ export declare function observationalMemory(config?: ObservationalMemoryConfig):
|
|
|
31
31
|
store: number;
|
|
32
32
|
};
|
|
33
33
|
hooks: {
|
|
34
|
-
init({ storage }: import("
|
|
34
|
+
init({ storage }: import("../../index.js").InitParams): Promise<{
|
|
35
35
|
state: ObservationalState;
|
|
36
36
|
}>;
|
|
37
|
-
recall({ state }: import("
|
|
38
|
-
items: import("
|
|
37
|
+
recall({ state }: import("../../index.js").RecallParams<ObservationalState>): Promise<{
|
|
38
|
+
items: import("../../index.js").InputMessageItem[];
|
|
39
39
|
tokenCount: number;
|
|
40
40
|
} | null>;
|
|
41
|
-
store({ newItems, state }: import("
|
|
41
|
+
store({ newItems, state }: import("../../index.js").StoreParams<ObservationalState>): Promise<{
|
|
42
42
|
state: {
|
|
43
43
|
buffer: string[];
|
|
44
44
|
bufferTokens: number;
|
|
@@ -46,7 +46,7 @@ export declare function observationalMemory(config?: ObservationalMemoryConfig):
|
|
|
46
46
|
version: number;
|
|
47
47
|
};
|
|
48
48
|
}>;
|
|
49
|
-
onSpawn({ parentState }: import("
|
|
49
|
+
onSpawn({ parentState }: import("../../index.js").SpawnParams<ObservationalState>): Promise<{
|
|
50
50
|
childState: ObservationalState;
|
|
51
51
|
}>;
|
|
52
52
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isOutputText } from '../../
|
|
3
|
-
import { Slot } from '../../types/memory';
|
|
1
|
+
import { Slot } from '../../types/memory.js';
|
|
2
|
+
import { createMessage, estimateTokens, isOutputText } from '../../util/message-helpers.js';
|
|
4
3
|
const DEFAULT_BUFFER_THRESHOLD_TOKENS = 2_000;
|
|
5
4
|
const DEFAULT_MAX_OBSERVATIONS = 50;
|
|
6
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { MemoryLayer, MemoryScope } from '../../types/memory.js';
|
|
2
|
+
import type { FlowNode } from '../flow-schema.js';
|
|
3
3
|
export declare const PlanPhase: {
|
|
4
4
|
readonly Idle: "idle";
|
|
5
5
|
readonly Planning: "planning";
|