deepagents 1.8.0 → 1.8.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/dist/index.cjs +158 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -6
- package/dist/index.d.ts +41 -6
- package/dist/index.js +158 -32
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.d.cts
CHANGED
|
@@ -1125,17 +1125,47 @@ declare function createSummarizationMiddleware(options: SummarizationMiddlewareO
|
|
|
1125
1125
|
}, z$1.core.$strip>, undefined, unknown, readonly (ClientTool | ServerTool)[]>;
|
|
1126
1126
|
//#endregion
|
|
1127
1127
|
//#region src/backends/store.d.ts
|
|
1128
|
+
/**
|
|
1129
|
+
* Options for StoreBackend constructor.
|
|
1130
|
+
*/
|
|
1131
|
+
interface StoreBackendOptions {
|
|
1132
|
+
/**
|
|
1133
|
+
* Custom namespace for store operations.
|
|
1134
|
+
*
|
|
1135
|
+
* Determines where files are stored in the LangGraph store, enabling
|
|
1136
|
+
* user-scoped, org-scoped, or any custom isolation pattern.
|
|
1137
|
+
*
|
|
1138
|
+
* If not provided, falls back to legacy behavior using assistantId from StateAndStore.
|
|
1139
|
+
*
|
|
1140
|
+
* @example
|
|
1141
|
+
* ```typescript
|
|
1142
|
+
* // User-scoped storage
|
|
1143
|
+
* new StoreBackend(stateAndStore, {
|
|
1144
|
+
* namespace: ["memories", orgId, userId, "filesystem"],
|
|
1145
|
+
* });
|
|
1146
|
+
*
|
|
1147
|
+
* // Org-scoped storage
|
|
1148
|
+
* new StoreBackend(stateAndStore, {
|
|
1149
|
+
* namespace: ["memories", orgId, "filesystem"],
|
|
1150
|
+
* });
|
|
1151
|
+
* ```
|
|
1152
|
+
*/
|
|
1153
|
+
namespace?: string[];
|
|
1154
|
+
}
|
|
1128
1155
|
/**
|
|
1129
1156
|
* Backend that stores files in LangGraph's BaseStore (persistent).
|
|
1130
1157
|
*
|
|
1131
1158
|
* Uses LangGraph's Store for persistent, cross-conversation storage.
|
|
1132
1159
|
* Files are organized via namespaces and persist across all threads.
|
|
1133
1160
|
*
|
|
1134
|
-
* The namespace can
|
|
1161
|
+
* The namespace can be customized via a factory function for flexible
|
|
1162
|
+
* isolation patterns (user-scoped, org-scoped, etc.), or falls back
|
|
1163
|
+
* to legacy assistant_id-based isolation.
|
|
1135
1164
|
*/
|
|
1136
1165
|
declare class StoreBackend implements BackendProtocol {
|
|
1137
1166
|
private stateAndStore;
|
|
1138
|
-
|
|
1167
|
+
private _namespace;
|
|
1168
|
+
constructor(stateAndStore: StateAndStore, options?: StoreBackendOptions);
|
|
1139
1169
|
/**
|
|
1140
1170
|
* Get the store instance.
|
|
1141
1171
|
*
|
|
@@ -1146,9 +1176,11 @@ declare class StoreBackend implements BackendProtocol {
|
|
|
1146
1176
|
/**
|
|
1147
1177
|
* Get the namespace for store operations.
|
|
1148
1178
|
*
|
|
1149
|
-
* If
|
|
1150
|
-
*
|
|
1151
|
-
* Otherwise
|
|
1179
|
+
* If a custom namespace was provided, returns it directly.
|
|
1180
|
+
*
|
|
1181
|
+
* Otherwise, falls back to legacy behavior:
|
|
1182
|
+
* - If assistantId is set: [assistantId, "filesystem"]
|
|
1183
|
+
* - Otherwise: ["filesystem"]
|
|
1152
1184
|
*/
|
|
1153
1185
|
protected getNamespace(): string[];
|
|
1154
1186
|
/**
|
|
@@ -1713,6 +1745,9 @@ declare abstract class BaseSandbox implements SandboxBackendProtocol {
|
|
|
1713
1745
|
*
|
|
1714
1746
|
* Uses downloadFiles() to read, performs string replacement in TypeScript,
|
|
1715
1747
|
* then uploadFiles() to write back. No runtime needed on the sandbox host.
|
|
1748
|
+
*
|
|
1749
|
+
* Memory-conscious: releases intermediate references early so the GC can
|
|
1750
|
+
* reclaim buffers before the next large allocation is made.
|
|
1716
1751
|
*/
|
|
1717
1752
|
edit(filePath: string, oldString: string, newString: string, replaceAll?: boolean): Promise<EditResult>;
|
|
1718
1753
|
}
|
|
@@ -2394,5 +2429,5 @@ declare function parseSkillMetadata(skillMdPath: string, source: "user" | "proje
|
|
|
2394
2429
|
*/
|
|
2395
2430
|
declare function listSkills(options: ListSkillsOptions): SkillMetadata[];
|
|
2396
2431
|
//#endregion
|
|
2397
|
-
export { type AgentMemoryMiddlewareOptions, type BackendFactory, type BackendProtocol, BaseSandbox, type CompiledSubAgent, CompositeBackend, type CreateDeepAgentParams, DEFAULT_GENERAL_PURPOSE_DESCRIPTION, DEFAULT_SUBAGENT_PROMPT, type DeepAgent, type DeepAgentTypeConfig, type DefaultDeepAgentTypeConfig, type EditResult, type ExecuteResponse, type ExtractSubAgentMiddleware, type FileData, type FileDownloadResponse, type FileInfo, type FileOperationError, type FileUploadResponse, FilesystemBackend, type FilesystemMiddlewareOptions, type FlattenSubAgentMiddleware, GENERAL_PURPOSE_SUBAGENT, type GrepMatch, type InferDeepAgentSubagents, type InferDeepAgentType, type InferStructuredResponse, type InferSubAgentMiddlewareStates, type InferSubagentByName, type InferSubagentReactAgentType, type ListSkillsOptions, type SkillMetadata as LoaderSkillMetadata, LocalShellBackend, type LocalShellBackendOptions, MAX_SKILL_DESCRIPTION_LENGTH, MAX_SKILL_FILE_SIZE, MAX_SKILL_NAME_LENGTH, type MaybePromise, type MemoryMiddlewareOptions, type MergedDeepAgentState, type ResolveDeepAgentTypeConfig, type SandboxBackendProtocol, type SandboxDeleteOptions, SandboxError, type SandboxErrorCode, type SandboxGetOrCreateOptions, type SandboxInfo, type SandboxListOptions, type SandboxListResponse, type Settings, type SettingsOptions, type SkillMetadata$1 as SkillMetadata, type SkillsMiddlewareOptions, StateBackend, StoreBackend, type SubAgent, type SubAgentMiddlewareOptions, type SupportedResponseFormat, TASK_SYSTEM_PROMPT, type WriteResult, computeSummarizationDefaults, createAgentMemoryMiddleware, createDeepAgent, createFilesystemMiddleware, createMemoryMiddleware, createPatchToolCallsMiddleware, createSettings, createSkillsMiddleware, createSubAgentMiddleware, createSummarizationMiddleware, filesValue, findProjectRoot, isSandboxBackend, listSkills, parseSkillMetadata };
|
|
2432
|
+
export { type AgentMemoryMiddlewareOptions, type BackendFactory, type BackendProtocol, BaseSandbox, type CompiledSubAgent, CompositeBackend, type CreateDeepAgentParams, DEFAULT_GENERAL_PURPOSE_DESCRIPTION, DEFAULT_SUBAGENT_PROMPT, type DeepAgent, type DeepAgentTypeConfig, type DefaultDeepAgentTypeConfig, type EditResult, type ExecuteResponse, type ExtractSubAgentMiddleware, type FileData, type FileDownloadResponse, type FileInfo, type FileOperationError, type FileUploadResponse, FilesystemBackend, type FilesystemMiddlewareOptions, type FlattenSubAgentMiddleware, GENERAL_PURPOSE_SUBAGENT, type GrepMatch, type InferDeepAgentSubagents, type InferDeepAgentType, type InferStructuredResponse, type InferSubAgentMiddlewareStates, type InferSubagentByName, type InferSubagentReactAgentType, type ListSkillsOptions, type SkillMetadata as LoaderSkillMetadata, LocalShellBackend, type LocalShellBackendOptions, MAX_SKILL_DESCRIPTION_LENGTH, MAX_SKILL_FILE_SIZE, MAX_SKILL_NAME_LENGTH, type MaybePromise, type MemoryMiddlewareOptions, type MergedDeepAgentState, type ResolveDeepAgentTypeConfig, type SandboxBackendProtocol, type SandboxDeleteOptions, SandboxError, type SandboxErrorCode, type SandboxGetOrCreateOptions, type SandboxInfo, type SandboxListOptions, type SandboxListResponse, type Settings, type SettingsOptions, type SkillMetadata$1 as SkillMetadata, type SkillsMiddlewareOptions, StateBackend, StoreBackend, type StoreBackendOptions, type SubAgent, type SubAgentMiddlewareOptions, type SupportedResponseFormat, TASK_SYSTEM_PROMPT, type WriteResult, computeSummarizationDefaults, createAgentMemoryMiddleware, createDeepAgent, createFilesystemMiddleware, createMemoryMiddleware, createPatchToolCallsMiddleware, createSettings, createSkillsMiddleware, createSubAgentMiddleware, createSummarizationMiddleware, filesValue, findProjectRoot, isSandboxBackend, listSkills, parseSkillMetadata };
|
|
2398
2433
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1125,17 +1125,47 @@ declare function createSummarizationMiddleware(options: SummarizationMiddlewareO
|
|
|
1125
1125
|
}, z$1.core.$strip>, undefined, unknown, readonly (ClientTool | ServerTool)[]>;
|
|
1126
1126
|
//#endregion
|
|
1127
1127
|
//#region src/backends/store.d.ts
|
|
1128
|
+
/**
|
|
1129
|
+
* Options for StoreBackend constructor.
|
|
1130
|
+
*/
|
|
1131
|
+
interface StoreBackendOptions {
|
|
1132
|
+
/**
|
|
1133
|
+
* Custom namespace for store operations.
|
|
1134
|
+
*
|
|
1135
|
+
* Determines where files are stored in the LangGraph store, enabling
|
|
1136
|
+
* user-scoped, org-scoped, or any custom isolation pattern.
|
|
1137
|
+
*
|
|
1138
|
+
* If not provided, falls back to legacy behavior using assistantId from StateAndStore.
|
|
1139
|
+
*
|
|
1140
|
+
* @example
|
|
1141
|
+
* ```typescript
|
|
1142
|
+
* // User-scoped storage
|
|
1143
|
+
* new StoreBackend(stateAndStore, {
|
|
1144
|
+
* namespace: ["memories", orgId, userId, "filesystem"],
|
|
1145
|
+
* });
|
|
1146
|
+
*
|
|
1147
|
+
* // Org-scoped storage
|
|
1148
|
+
* new StoreBackend(stateAndStore, {
|
|
1149
|
+
* namespace: ["memories", orgId, "filesystem"],
|
|
1150
|
+
* });
|
|
1151
|
+
* ```
|
|
1152
|
+
*/
|
|
1153
|
+
namespace?: string[];
|
|
1154
|
+
}
|
|
1128
1155
|
/**
|
|
1129
1156
|
* Backend that stores files in LangGraph's BaseStore (persistent).
|
|
1130
1157
|
*
|
|
1131
1158
|
* Uses LangGraph's Store for persistent, cross-conversation storage.
|
|
1132
1159
|
* Files are organized via namespaces and persist across all threads.
|
|
1133
1160
|
*
|
|
1134
|
-
* The namespace can
|
|
1161
|
+
* The namespace can be customized via a factory function for flexible
|
|
1162
|
+
* isolation patterns (user-scoped, org-scoped, etc.), or falls back
|
|
1163
|
+
* to legacy assistant_id-based isolation.
|
|
1135
1164
|
*/
|
|
1136
1165
|
declare class StoreBackend implements BackendProtocol {
|
|
1137
1166
|
private stateAndStore;
|
|
1138
|
-
|
|
1167
|
+
private _namespace;
|
|
1168
|
+
constructor(stateAndStore: StateAndStore, options?: StoreBackendOptions);
|
|
1139
1169
|
/**
|
|
1140
1170
|
* Get the store instance.
|
|
1141
1171
|
*
|
|
@@ -1146,9 +1176,11 @@ declare class StoreBackend implements BackendProtocol {
|
|
|
1146
1176
|
/**
|
|
1147
1177
|
* Get the namespace for store operations.
|
|
1148
1178
|
*
|
|
1149
|
-
* If
|
|
1150
|
-
*
|
|
1151
|
-
* Otherwise
|
|
1179
|
+
* If a custom namespace was provided, returns it directly.
|
|
1180
|
+
*
|
|
1181
|
+
* Otherwise, falls back to legacy behavior:
|
|
1182
|
+
* - If assistantId is set: [assistantId, "filesystem"]
|
|
1183
|
+
* - Otherwise: ["filesystem"]
|
|
1152
1184
|
*/
|
|
1153
1185
|
protected getNamespace(): string[];
|
|
1154
1186
|
/**
|
|
@@ -1713,6 +1745,9 @@ declare abstract class BaseSandbox implements SandboxBackendProtocol {
|
|
|
1713
1745
|
*
|
|
1714
1746
|
* Uses downloadFiles() to read, performs string replacement in TypeScript,
|
|
1715
1747
|
* then uploadFiles() to write back. No runtime needed on the sandbox host.
|
|
1748
|
+
*
|
|
1749
|
+
* Memory-conscious: releases intermediate references early so the GC can
|
|
1750
|
+
* reclaim buffers before the next large allocation is made.
|
|
1716
1751
|
*/
|
|
1717
1752
|
edit(filePath: string, oldString: string, newString: string, replaceAll?: boolean): Promise<EditResult>;
|
|
1718
1753
|
}
|
|
@@ -2394,5 +2429,5 @@ declare function parseSkillMetadata(skillMdPath: string, source: "user" | "proje
|
|
|
2394
2429
|
*/
|
|
2395
2430
|
declare function listSkills(options: ListSkillsOptions): SkillMetadata[];
|
|
2396
2431
|
//#endregion
|
|
2397
|
-
export { type AgentMemoryMiddlewareOptions, type BackendFactory, type BackendProtocol, BaseSandbox, type CompiledSubAgent, CompositeBackend, type CreateDeepAgentParams, DEFAULT_GENERAL_PURPOSE_DESCRIPTION, DEFAULT_SUBAGENT_PROMPT, type DeepAgent, type DeepAgentTypeConfig, type DefaultDeepAgentTypeConfig, type EditResult, type ExecuteResponse, type ExtractSubAgentMiddleware, type FileData, type FileDownloadResponse, type FileInfo, type FileOperationError, type FileUploadResponse, FilesystemBackend, type FilesystemMiddlewareOptions, type FlattenSubAgentMiddleware, GENERAL_PURPOSE_SUBAGENT, type GrepMatch, type InferDeepAgentSubagents, type InferDeepAgentType, type InferStructuredResponse, type InferSubAgentMiddlewareStates, type InferSubagentByName, type InferSubagentReactAgentType, type ListSkillsOptions, type SkillMetadata as LoaderSkillMetadata, LocalShellBackend, type LocalShellBackendOptions, MAX_SKILL_DESCRIPTION_LENGTH, MAX_SKILL_FILE_SIZE, MAX_SKILL_NAME_LENGTH, type MaybePromise, type MemoryMiddlewareOptions, type MergedDeepAgentState, type ResolveDeepAgentTypeConfig, type SandboxBackendProtocol, type SandboxDeleteOptions, SandboxError, type SandboxErrorCode, type SandboxGetOrCreateOptions, type SandboxInfo, type SandboxListOptions, type SandboxListResponse, type Settings, type SettingsOptions, type SkillMetadata$1 as SkillMetadata, type SkillsMiddlewareOptions, StateBackend, StoreBackend, type SubAgent, type SubAgentMiddlewareOptions, type SupportedResponseFormat, TASK_SYSTEM_PROMPT, type WriteResult, computeSummarizationDefaults, createAgentMemoryMiddleware, createDeepAgent, createFilesystemMiddleware, createMemoryMiddleware, createPatchToolCallsMiddleware, createSettings, createSkillsMiddleware, createSubAgentMiddleware, createSummarizationMiddleware, filesValue, findProjectRoot, isSandboxBackend, listSkills, parseSkillMetadata };
|
|
2432
|
+
export { type AgentMemoryMiddlewareOptions, type BackendFactory, type BackendProtocol, BaseSandbox, type CompiledSubAgent, CompositeBackend, type CreateDeepAgentParams, DEFAULT_GENERAL_PURPOSE_DESCRIPTION, DEFAULT_SUBAGENT_PROMPT, type DeepAgent, type DeepAgentTypeConfig, type DefaultDeepAgentTypeConfig, type EditResult, type ExecuteResponse, type ExtractSubAgentMiddleware, type FileData, type FileDownloadResponse, type FileInfo, type FileOperationError, type FileUploadResponse, FilesystemBackend, type FilesystemMiddlewareOptions, type FlattenSubAgentMiddleware, GENERAL_PURPOSE_SUBAGENT, type GrepMatch, type InferDeepAgentSubagents, type InferDeepAgentType, type InferStructuredResponse, type InferSubAgentMiddlewareStates, type InferSubagentByName, type InferSubagentReactAgentType, type ListSkillsOptions, type SkillMetadata as LoaderSkillMetadata, LocalShellBackend, type LocalShellBackendOptions, MAX_SKILL_DESCRIPTION_LENGTH, MAX_SKILL_FILE_SIZE, MAX_SKILL_NAME_LENGTH, type MaybePromise, type MemoryMiddlewareOptions, type MergedDeepAgentState, type ResolveDeepAgentTypeConfig, type SandboxBackendProtocol, type SandboxDeleteOptions, SandboxError, type SandboxErrorCode, type SandboxGetOrCreateOptions, type SandboxInfo, type SandboxListOptions, type SandboxListResponse, type Settings, type SettingsOptions, type SkillMetadata$1 as SkillMetadata, type SkillsMiddlewareOptions, StateBackend, StoreBackend, type StoreBackendOptions, type SubAgent, type SubAgentMiddlewareOptions, type SupportedResponseFormat, TASK_SYSTEM_PROMPT, type WriteResult, computeSummarizationDefaults, createAgentMemoryMiddleware, createDeepAgent, createFilesystemMiddleware, createMemoryMiddleware, createPatchToolCallsMiddleware, createSettings, createSkillsMiddleware, createSubAgentMiddleware, createSummarizationMiddleware, filesValue, findProjectRoot, isSandboxBackend, listSkills, parseSkillMetadata };
|
|
2398
2433
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1049,7 +1049,13 @@ function createFilesystemMiddleware(options = {}) {
|
|
|
1049
1049
|
message: new ToolMessage({
|
|
1050
1050
|
content: TOO_LARGE_TOOL_MSG.replace("{tool_call_id}", msg.tool_call_id).replace("{file_path}", evictPath).replace("{content_sample}", contentSample),
|
|
1051
1051
|
tool_call_id: msg.tool_call_id,
|
|
1052
|
-
name: msg.name
|
|
1052
|
+
name: msg.name,
|
|
1053
|
+
id: msg.id,
|
|
1054
|
+
artifact: msg.artifact,
|
|
1055
|
+
status: msg.status,
|
|
1056
|
+
metadata: msg.metadata,
|
|
1057
|
+
additional_kwargs: msg.additional_kwargs,
|
|
1058
|
+
response_metadata: msg.response_metadata
|
|
1053
1059
|
}),
|
|
1054
1060
|
filesUpdate: writeResult.filesUpdate
|
|
1055
1061
|
};
|
|
@@ -1327,16 +1333,28 @@ function filterStateForSubagent(state) {
|
|
|
1327
1333
|
return filtered;
|
|
1328
1334
|
}
|
|
1329
1335
|
/**
|
|
1336
|
+
* Invalid tool message block types
|
|
1337
|
+
*/
|
|
1338
|
+
const INVALID_TOOL_MESSAGE_BLOCK_TYPES = [
|
|
1339
|
+
"tool_use",
|
|
1340
|
+
"thinking",
|
|
1341
|
+
"redacted_thinking"
|
|
1342
|
+
];
|
|
1343
|
+
/**
|
|
1330
1344
|
* Create Command with filtered state update from subagent result
|
|
1331
1345
|
*/
|
|
1332
1346
|
function returnCommandWithStateUpdate(result, toolCallId) {
|
|
1333
1347
|
const stateUpdate = filterStateForSubagent(result);
|
|
1334
1348
|
const messages = result.messages;
|
|
1335
|
-
|
|
1349
|
+
let content = (messages?.[messages.length - 1])?.content || "Task completed";
|
|
1350
|
+
if (Array.isArray(content)) {
|
|
1351
|
+
content = content.filter((block) => !INVALID_TOOL_MESSAGE_BLOCK_TYPES.includes(block.type));
|
|
1352
|
+
if (content.length === 0) content = "Task completed";
|
|
1353
|
+
}
|
|
1336
1354
|
return new Command({ update: {
|
|
1337
1355
|
...stateUpdate,
|
|
1338
1356
|
messages: [new ToolMessage({
|
|
1339
|
-
content
|
|
1357
|
+
content,
|
|
1340
1358
|
tool_call_id: toolCallId,
|
|
1341
1359
|
name: "task"
|
|
1342
1360
|
})]
|
|
@@ -2658,31 +2676,44 @@ function createSummarizationMiddleware(options) {
|
|
|
2658
2676
|
return messages.filter((msg) => !isSummaryMessage(msg));
|
|
2659
2677
|
}
|
|
2660
2678
|
/**
|
|
2661
|
-
* Offload messages to backend.
|
|
2679
|
+
* Offload messages to backend by appending to the history file.
|
|
2680
|
+
*
|
|
2681
|
+
* Uses uploadFiles() directly with raw byte concatenation instead of
|
|
2682
|
+
* edit() to avoid downloading the file twice and performing a full
|
|
2683
|
+
* string search-and-replace. This keeps peak memory at ~2x file size
|
|
2684
|
+
* (existing bytes + combined bytes) instead of ~6x with the old
|
|
2685
|
+
* download → edit(oldContent, newContent) approach.
|
|
2662
2686
|
*/
|
|
2663
2687
|
async function offloadToBackend(resolvedBackend, messages, state) {
|
|
2664
|
-
const
|
|
2688
|
+
const filePath = getHistoryPath(state);
|
|
2665
2689
|
const filteredMessages = filterSummaryMessages(messages);
|
|
2666
2690
|
const newSection = `## Summarized at ${(/* @__PURE__ */ new Date()).toISOString()}\n\n${getBufferString(filteredMessages)}\n\n`;
|
|
2667
|
-
|
|
2668
|
-
try {
|
|
2669
|
-
if (resolvedBackend.downloadFiles) {
|
|
2670
|
-
const responses = await resolvedBackend.downloadFiles([path]);
|
|
2671
|
-
if (responses.length > 0 && responses[0].content && !responses[0].error) existingContent = new TextDecoder().decode(responses[0].content);
|
|
2672
|
-
}
|
|
2673
|
-
} catch {}
|
|
2674
|
-
const combinedContent = existingContent + newSection;
|
|
2691
|
+
const sectionBytes = new TextEncoder().encode(newSection);
|
|
2675
2692
|
try {
|
|
2693
|
+
let existingBytes = null;
|
|
2694
|
+
if (resolvedBackend.downloadFiles) try {
|
|
2695
|
+
const responses = await resolvedBackend.downloadFiles([filePath]);
|
|
2696
|
+
if (responses.length > 0 && responses[0].content && !responses[0].error) existingBytes = responses[0].content;
|
|
2697
|
+
} catch {}
|
|
2676
2698
|
let result;
|
|
2677
|
-
if (
|
|
2678
|
-
|
|
2699
|
+
if (existingBytes && resolvedBackend.uploadFiles) {
|
|
2700
|
+
const combined = new Uint8Array(existingBytes.byteLength + sectionBytes.byteLength);
|
|
2701
|
+
combined.set(existingBytes, 0);
|
|
2702
|
+
combined.set(sectionBytes, existingBytes.byteLength);
|
|
2703
|
+
const uploadResults = await resolvedBackend.uploadFiles([[filePath, combined]]);
|
|
2704
|
+
result = uploadResults[0].error ? { error: uploadResults[0].error } : { path: filePath };
|
|
2705
|
+
} else if (!existingBytes) result = await resolvedBackend.write(filePath, newSection);
|
|
2706
|
+
else {
|
|
2707
|
+
const existingContent = new TextDecoder().decode(existingBytes);
|
|
2708
|
+
result = await resolvedBackend.edit(filePath, existingContent, existingContent + newSection);
|
|
2709
|
+
}
|
|
2679
2710
|
if (result.error) {
|
|
2680
|
-
console.warn(`Failed to offload conversation history to ${
|
|
2711
|
+
console.warn(`Failed to offload conversation history to ${filePath}: ${result.error}`);
|
|
2681
2712
|
return null;
|
|
2682
2713
|
}
|
|
2683
|
-
return
|
|
2714
|
+
return filePath;
|
|
2684
2715
|
} catch (e) {
|
|
2685
|
-
console.warn(`Exception offloading conversation history to ${
|
|
2716
|
+
console.warn(`Exception offloading conversation history to ${filePath}:`, e);
|
|
2686
2717
|
return null;
|
|
2687
2718
|
}
|
|
2688
2719
|
}
|
|
@@ -2872,18 +2903,43 @@ ${summary}
|
|
|
2872
2903
|
|
|
2873
2904
|
//#endregion
|
|
2874
2905
|
//#region src/backends/store.ts
|
|
2906
|
+
const NAMESPACE_COMPONENT_RE = /^[A-Za-z0-9\-_.@+:~]+$/;
|
|
2907
|
+
/**
|
|
2908
|
+
* Validate a namespace array.
|
|
2909
|
+
*
|
|
2910
|
+
* Each component must be a non-empty string containing only safe characters:
|
|
2911
|
+
* alphanumeric (a-z, A-Z, 0-9), hyphen (-), underscore (_), dot (.),
|
|
2912
|
+
* at sign (@), plus (+), colon (:), and tilde (~).
|
|
2913
|
+
*
|
|
2914
|
+
* Characters like *, ?, [, ], {, } etc. are rejected to prevent
|
|
2915
|
+
* wildcard or glob injection in store lookups.
|
|
2916
|
+
*/
|
|
2917
|
+
function validateNamespace(namespace) {
|
|
2918
|
+
if (namespace.length === 0) throw new Error("Namespace array must not be empty.");
|
|
2919
|
+
for (let i = 0; i < namespace.length; i++) {
|
|
2920
|
+
const component = namespace[i];
|
|
2921
|
+
if (typeof component !== "string") throw new TypeError(`Namespace component at index ${i} must be a string, got ${typeof component}.`);
|
|
2922
|
+
if (!component) throw new Error(`Namespace component at index ${i} must not be empty.`);
|
|
2923
|
+
if (!NAMESPACE_COMPONENT_RE.test(component)) throw new Error(`Namespace component at index ${i} contains disallowed characters: "${component}". Only alphanumeric characters, hyphens, underscores, dots, @, +, colons, and tildes are allowed.`);
|
|
2924
|
+
}
|
|
2925
|
+
return namespace;
|
|
2926
|
+
}
|
|
2875
2927
|
/**
|
|
2876
2928
|
* Backend that stores files in LangGraph's BaseStore (persistent).
|
|
2877
2929
|
*
|
|
2878
2930
|
* Uses LangGraph's Store for persistent, cross-conversation storage.
|
|
2879
2931
|
* Files are organized via namespaces and persist across all threads.
|
|
2880
2932
|
*
|
|
2881
|
-
* The namespace can
|
|
2933
|
+
* The namespace can be customized via a factory function for flexible
|
|
2934
|
+
* isolation patterns (user-scoped, org-scoped, etc.), or falls back
|
|
2935
|
+
* to legacy assistant_id-based isolation.
|
|
2882
2936
|
*/
|
|
2883
2937
|
var StoreBackend = class {
|
|
2884
2938
|
stateAndStore;
|
|
2885
|
-
|
|
2939
|
+
_namespace;
|
|
2940
|
+
constructor(stateAndStore, options) {
|
|
2886
2941
|
this.stateAndStore = stateAndStore;
|
|
2942
|
+
if (options?.namespace) this._namespace = validateNamespace(options.namespace);
|
|
2887
2943
|
}
|
|
2888
2944
|
/**
|
|
2889
2945
|
* Get the store instance.
|
|
@@ -2899,15 +2955,17 @@ var StoreBackend = class {
|
|
|
2899
2955
|
/**
|
|
2900
2956
|
* Get the namespace for store operations.
|
|
2901
2957
|
*
|
|
2902
|
-
* If
|
|
2903
|
-
*
|
|
2904
|
-
* Otherwise
|
|
2958
|
+
* If a custom namespace was provided, returns it directly.
|
|
2959
|
+
*
|
|
2960
|
+
* Otherwise, falls back to legacy behavior:
|
|
2961
|
+
* - If assistantId is set: [assistantId, "filesystem"]
|
|
2962
|
+
* - Otherwise: ["filesystem"]
|
|
2905
2963
|
*/
|
|
2906
2964
|
getNamespace() {
|
|
2907
|
-
|
|
2965
|
+
if (this._namespace) return this._namespace;
|
|
2908
2966
|
const assistantId = this.stateAndStore.assistantId;
|
|
2909
|
-
if (assistantId) return [assistantId,
|
|
2910
|
-
return [
|
|
2967
|
+
if (assistantId) return [assistantId, "filesystem"];
|
|
2968
|
+
return ["filesystem"];
|
|
2911
2969
|
}
|
|
2912
2970
|
/**
|
|
2913
2971
|
* Convert a store Item to FileData format.
|
|
@@ -4567,17 +4625,85 @@ var BaseSandbox = class {
|
|
|
4567
4625
|
*
|
|
4568
4626
|
* Uses downloadFiles() to read, performs string replacement in TypeScript,
|
|
4569
4627
|
* then uploadFiles() to write back. No runtime needed on the sandbox host.
|
|
4628
|
+
*
|
|
4629
|
+
* Memory-conscious: releases intermediate references early so the GC can
|
|
4630
|
+
* reclaim buffers before the next large allocation is made.
|
|
4570
4631
|
*/
|
|
4571
4632
|
async edit(filePath, oldString, newString, replaceAll = false) {
|
|
4572
4633
|
const results = await this.downloadFiles([filePath]);
|
|
4573
4634
|
if (results[0].error || !results[0].content) return { error: `Error: File '${filePath}' not found` };
|
|
4574
4635
|
const text = new TextDecoder().decode(results[0].content);
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4636
|
+
results[0].content = null;
|
|
4637
|
+
/**
|
|
4638
|
+
* are we editing an empty file?
|
|
4639
|
+
*/
|
|
4640
|
+
if (oldString.length === 0) {
|
|
4641
|
+
/**
|
|
4642
|
+
* if the file is not empty, we cannot edit it with an empty oldString
|
|
4643
|
+
*/
|
|
4644
|
+
if (text.length !== 0) return { error: "oldString must not be empty unless the file is empty" };
|
|
4645
|
+
/**
|
|
4646
|
+
* if the newString is empty, we can just return the file as is
|
|
4647
|
+
*/
|
|
4648
|
+
if (newString.length === 0) return {
|
|
4649
|
+
path: filePath,
|
|
4650
|
+
filesUpdate: null,
|
|
4651
|
+
occurrences: 0
|
|
4652
|
+
};
|
|
4653
|
+
/**
|
|
4654
|
+
* if the newString is not empty, we can edit the file
|
|
4655
|
+
*/
|
|
4656
|
+
const encoded = new TextEncoder().encode(newString);
|
|
4657
|
+
const uploadResults = await this.uploadFiles([[filePath, encoded]]);
|
|
4658
|
+
/**
|
|
4659
|
+
* if the upload fails, we return an error
|
|
4660
|
+
*/
|
|
4661
|
+
if (uploadResults[0].error) return { error: `Failed to write edited file '${filePath}': ${uploadResults[0].error}` };
|
|
4662
|
+
return {
|
|
4663
|
+
path: filePath,
|
|
4664
|
+
filesUpdate: null,
|
|
4665
|
+
occurrences: 1
|
|
4666
|
+
};
|
|
4667
|
+
}
|
|
4668
|
+
const firstIdx = text.indexOf(oldString);
|
|
4669
|
+
if (firstIdx === -1) return { error: `String not found in file '${filePath}'` };
|
|
4670
|
+
if (oldString === newString) return {
|
|
4671
|
+
path: filePath,
|
|
4672
|
+
filesUpdate: null,
|
|
4673
|
+
occurrences: 1
|
|
4674
|
+
};
|
|
4675
|
+
let newText;
|
|
4676
|
+
let count;
|
|
4677
|
+
if (replaceAll) {
|
|
4678
|
+
newText = text.replaceAll(oldString, newString);
|
|
4679
|
+
/**
|
|
4680
|
+
* Derive count from the length delta to avoid a separate O(n) counting pass
|
|
4681
|
+
*/
|
|
4682
|
+
const lenDiff = oldString.length - newString.length;
|
|
4683
|
+
if (lenDiff !== 0) count = (text.length - newText.length) / lenDiff;
|
|
4684
|
+
else {
|
|
4685
|
+
/**
|
|
4686
|
+
* Lengths are equal — count via indexOf (we already found the first)
|
|
4687
|
+
*/
|
|
4688
|
+
count = 1;
|
|
4689
|
+
let pos = firstIdx + oldString.length;
|
|
4690
|
+
while (pos <= text.length) {
|
|
4691
|
+
const idx = text.indexOf(oldString, pos);
|
|
4692
|
+
if (idx === -1) break;
|
|
4693
|
+
count++;
|
|
4694
|
+
pos = idx + oldString.length;
|
|
4695
|
+
}
|
|
4696
|
+
}
|
|
4697
|
+
} else {
|
|
4698
|
+
if (text.indexOf(oldString, firstIdx + oldString.length) !== -1) return { error: `Multiple occurrences found in '${filePath}'. Use replaceAll=true to replace all.` };
|
|
4699
|
+
count = 1;
|
|
4700
|
+
/**
|
|
4701
|
+
* Build result from the known index — avoids a redundant search by .replace()
|
|
4702
|
+
*/
|
|
4703
|
+
newText = text.slice(0, firstIdx) + newString + text.slice(firstIdx + oldString.length);
|
|
4704
|
+
}
|
|
4705
|
+
const encoded = new TextEncoder().encode(newText);
|
|
4706
|
+
const uploadResults = await this.uploadFiles([[filePath, encoded]]);
|
|
4581
4707
|
if (uploadResults[0].error) return { error: `Failed to write edited file '${filePath}': ${uploadResults[0].error}` };
|
|
4582
4708
|
return {
|
|
4583
4709
|
path: filePath,
|