@letta-ai/letta-code 0.27.18 → 0.27.20
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/app-server-client.js +11 -1
- package/dist/app-server-client.js.map +3 -3
- package/dist/types/app-server-client.d.ts +4 -1
- package/dist/types/app-server-client.d.ts.map +1 -1
- package/dist/types/types/protocol_v2.d.ts +1 -1
- package/dist/types/types/protocol_v2.d.ts.map +1 -1
- package/docs/examples/mods/README.md +60 -0
- package/docs/examples/mods/learning/memory-citations.env.json +165 -0
- package/docs/examples/mods/learning/uv-pip-install.env.json +199 -0
- package/docs/examples/mods/memory-citations.ts +347 -0
- package/letta.js +4947 -1711
- package/package.json +4 -2
- package/scripts/mod-learning/learn-mod.ts +306 -0
- package/skills/{context_doctor → context-doctor}/SKILL.md +1 -1
- package/skills/creating-mods/SKILL.md +4 -1
- package/skills/creating-mods/references/events.md +25 -5
- package/skills/creating-mods/references/ui.md +23 -0
- package/skills/generating-mod-envs/SKILL.md +130 -0
- package/skills/generating-mod-envs/assets/mod-learning-env.template.json +57 -0
- package/skills/generating-mod-envs/scripts/validate-mod-env.ts +261 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Memory citation mod with wiki-link [[path]] format",
|
|
3
|
+
"slug": "memory-citations",
|
|
4
|
+
"targetModName": "memory-citations.ts",
|
|
5
|
+
"objective": "Learn a trusted local mod that causes the agent to cite its memory sources inline using the Wikipedia-style format [[path]] whenever the agent's response is clearly influenced by content from a memory file. The mod must inject a turn_start system reminder describing the citation policy, track memory-file reads via tool_start events, and expose a memory_citation_snapshot tool so the agent can see which memory paths it accessed before answering.",
|
|
6
|
+
"requirements": [
|
|
7
|
+
"On turn_start, inject a system message reminding the agent to cite each memory block that clearly influenced its response using the exact inline format [[path]], where path is the memory-relative path (e.g. [[reference/notes.md]]). The reminder must state: only cite when memory clearly influenced the answer, never invent citations, and only cite paths returned by the memory_citation_snapshot tool. The reminder must NOT instruct the agent to call memory_citation_snapshot unconditionally — the agent should only call it when it has actually read memory files during the turn.",
|
|
8
|
+
"On tool_start, observe tool calls whose arguments reference files inside the active memory directory. Treat Read/Glob/Grep/LS-style tools as high-confidence reads. Treat Bash/ShellCommand/exec_command as medium-confidence when the command string references $MEMORY_DIR or the absolute memory path.",
|
|
9
|
+
"Use ctx.memfs.memoryDir when available, falling back to process.env.MEMORY_DIR.",
|
|
10
|
+
"Register a read-only tool named memory_citation_snapshot with no parameters, requiresApproval false, parallelSafe true. It returns JSON with citationCount and a citations array containing path, confidence, evidence, toolName, toolCallId, and observedAt.",
|
|
11
|
+
"Reset per-conversation citation state at the start of each turn.",
|
|
12
|
+
"Never invent citations. The snapshot tool must only return paths actually observed from tool_start events.",
|
|
13
|
+
"The turn_start reminder must include a concrete example of the citation format such as [[reference/notes.md]]."
|
|
14
|
+
],
|
|
15
|
+
"candidateDiversityHints": [
|
|
16
|
+
"Use a conservative reminder and make memory_citation_snapshot the sole source of citeable paths; prefer simple Map-backed per-conversation state.",
|
|
17
|
+
"Focus on robust path normalization for absolute MEMORY_DIR paths, $MEMORY_DIR, ${MEMORY_DIR}, and memory-relative paths.",
|
|
18
|
+
"Focus on negative controls: avoid over-eager citations when no memory path was observed or when the answer does not draw on memory.",
|
|
19
|
+
"Use a minimal implementation with explicit tool-name allowlists and deduplication by memory-relative path.",
|
|
20
|
+
"Focus on shell-command evidence parsing while keeping read/list/search tools high-confidence and shell references medium-confidence."
|
|
21
|
+
],
|
|
22
|
+
"modApiHints": [
|
|
23
|
+
"The mod runtime accepts TypeScript files in LETTA_MODS_DIR and calls export function activate(letta) or a default export.",
|
|
24
|
+
"letta.events.on(\"turn_start\", handler) can mutate event.input or return a replacement input.",
|
|
25
|
+
"letta.events.on(\"tool_start\", handler) receives event.toolName, event.args, event.toolCallId, and event.conversationId.",
|
|
26
|
+
"letta.tools.register({ name, description, parameters, requiresApproval, parallelSafe, run }) registers a tool available to the model.",
|
|
27
|
+
"For eval compatibility, the snapshot tool must be named exactly memory_citation_snapshot.",
|
|
28
|
+
"For turn_start reminders, append a separate { type: \"message\", role: \"system\", content: reminder } object to event.input. Do not concatenate onto an existing message content field because content may be structured parts.",
|
|
29
|
+
"For tool run handlers, ctx.conversation.id is the active conversation id; use it to retrieve state keyed by event.conversationId.",
|
|
30
|
+
"Avoid fragile generated regex strings with embedded quote characters; simple string matching/splitting is fine. The candidate must be syntactically valid TypeScript."
|
|
31
|
+
],
|
|
32
|
+
"examples": [
|
|
33
|
+
{
|
|
34
|
+
"input": "The agent reads reference/notes.md with a Read tool, then answers a question drawing on that file's content.",
|
|
35
|
+
"expected": "The answer includes the inline citation [[reference/notes.md]] somewhere in the response."
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"input": "The agent runs Bash with cat $MEMORY_DIR/reference/mod-learning.md, then answers using information from that file.",
|
|
39
|
+
"expected": "The answer includes the inline citation [[reference/mod-learning.md]] somewhere in the response."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"input": "The agent reads a non-memory file like /etc/hosts.",
|
|
43
|
+
"expected": "No memory citation is included for that file since it is not in the memory directory."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"input": "The agent reads a memory file but the answer does not draw on its content.",
|
|
47
|
+
"expected": "No memory citation is included because the memory did not clearly influence the response."
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"evaluation": {
|
|
51
|
+
"outputFormat": "stream-json",
|
|
52
|
+
"timeoutMs": 900000,
|
|
53
|
+
"maxTurns": 8,
|
|
54
|
+
"forbiddenTraceMarkers": [
|
|
55
|
+
"[mods] failed to load",
|
|
56
|
+
"[extensions] failed to load",
|
|
57
|
+
"loaded 0 mod(s)",
|
|
58
|
+
"loaded 0 extension(s)"
|
|
59
|
+
],
|
|
60
|
+
"scenarios": [
|
|
61
|
+
{
|
|
62
|
+
"name": "mod-loads",
|
|
63
|
+
"assertions": [
|
|
64
|
+
{
|
|
65
|
+
"type": "mod_loads",
|
|
66
|
+
"expectedLoadedCount": 1
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"name": "turn-start-reminder",
|
|
72
|
+
"assertions": [
|
|
73
|
+
{
|
|
74
|
+
"type": "turn_start_injects_message",
|
|
75
|
+
"role": "system",
|
|
76
|
+
"contains": ["[[", "]]", "cite", "memory"],
|
|
77
|
+
"notContains": ["unconditionally", "always call"],
|
|
78
|
+
"input": [
|
|
79
|
+
{
|
|
80
|
+
"type": "message",
|
|
81
|
+
"role": "user",
|
|
82
|
+
"content": "What is the deployment target for this project?"
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"name": "tool-start-tracks-read",
|
|
90
|
+
"assertions": [
|
|
91
|
+
{
|
|
92
|
+
"type": "tool_start_rewrites_args",
|
|
93
|
+
"toolName": "Read",
|
|
94
|
+
"args": {
|
|
95
|
+
"file_path": "/tmp/mem-test/reference/notes.md"
|
|
96
|
+
},
|
|
97
|
+
"expectArgs": {
|
|
98
|
+
"file_path": "/tmp/mem-test/reference/notes.md"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"name": "tool-start-preserves-non-memory-read",
|
|
105
|
+
"assertions": [
|
|
106
|
+
{
|
|
107
|
+
"type": "tool_start_preserves_args",
|
|
108
|
+
"toolName": "Read",
|
|
109
|
+
"args": {
|
|
110
|
+
"file_path": "/etc/hosts"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"name": "implicit-memory-citation",
|
|
117
|
+
"memoryFiles": {
|
|
118
|
+
"reference/mod-learning.md": "# Project configuration\n\nThe deployment target for this project is CITATION-DOGFOOD-OK. All releases must be tagged with this target name before pushing to the registry.\n"
|
|
119
|
+
},
|
|
120
|
+
"prompt": "What is the deployment target for this project? Read the file $MEMORY_DIR/reference/mod-learning.md to find the answer.",
|
|
121
|
+
"requiredResultMarkers": [
|
|
122
|
+
"CITATION-DOGFOOD-OK",
|
|
123
|
+
"[[reference/mod-learning.md]]"
|
|
124
|
+
],
|
|
125
|
+
"requiredTraceMarkers": ["memory_citation_snapshot"],
|
|
126
|
+
"forbiddenResultMarkers": [
|
|
127
|
+
"No explicit memory file reads were observed",
|
|
128
|
+
"memory_citation_snapshot tool is not available"
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"name": "exact-relevant-path",
|
|
133
|
+
"memoryFiles": {
|
|
134
|
+
"reference/mod-learning.md": "# Deployment target\n\nThe deployment target is NOT-THIS-FILE. This file is intentionally irrelevant for the release-channel question.\n",
|
|
135
|
+
"reference/release-policy.md": "# Release policy\n\nThe release channel for the project is CANARY-WIKI-LINK. Use this channel for staged rollouts.\n"
|
|
136
|
+
},
|
|
137
|
+
"prompt": "What is the release channel for this project? Read the files under $MEMORY_DIR/reference/ to find the answer.",
|
|
138
|
+
"requiredResultMarkers": [
|
|
139
|
+
"CANARY-WIKI-LINK",
|
|
140
|
+
"[[reference/release-policy.md]]"
|
|
141
|
+
],
|
|
142
|
+
"requiredTraceMarkers": ["memory_citation_snapshot"],
|
|
143
|
+
"forbiddenResultMarkers": [
|
|
144
|
+
"[[reference/mod-learning.md]]",
|
|
145
|
+
"NOT-THIS-FILE"
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"name": "negative-control-no-memory-use",
|
|
150
|
+
"memoryFiles": {
|
|
151
|
+
"reference/mod-learning.md": "# Project configuration\n\nThe deployment target for this project is CITATION-DOGFOOD-OK.\n"
|
|
152
|
+
},
|
|
153
|
+
"prompt": "Answer without checking memory: what is 2 + 2?",
|
|
154
|
+
"requiredResultMarkers": ["4"],
|
|
155
|
+
"forbiddenResultMarkers": [
|
|
156
|
+
"[[",
|
|
157
|
+
"reference/mod-learning.md",
|
|
158
|
+
"Memory references:",
|
|
159
|
+
"CITATION-DOGFOOD-OK"
|
|
160
|
+
],
|
|
161
|
+
"forbiddenTraceMarkers": ["\"tool_name\":\"memory_citation_snapshot\""]
|
|
162
|
+
}
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Use uv instead of pip for Python package installs",
|
|
3
|
+
"slug": "uv-pip-install",
|
|
4
|
+
"targetModName": "uv-pip-install.ts",
|
|
5
|
+
"objective": "Learn a trusted local mod that ensures the agent uses uv pip install instead of pip install or python -m pip install when installing Python packages. The mod must inject a turn_start reminder and rewrite Bash tool_start command args for pip install forms. It must not rewrite non-install pip subcommands or non-Python package managers.",
|
|
6
|
+
"requirements": [
|
|
7
|
+
"On turn_start, inject a system message reminding the agent to use uv pip install instead of pip install or python -m pip install when installing Python packages.",
|
|
8
|
+
"On tool_start, intercept Bash tool calls whose command argument contains a pip install command and rewrite it to use uv pip install instead.",
|
|
9
|
+
"Rewrite 'pip install <package>' to 'uv pip install <package>', preserving all flags and arguments after install.",
|
|
10
|
+
"Rewrite 'python -m pip install <package>' and 'python3 -m pip install <package>' to 'uv pip install <package>', preserving all flags and arguments after install.",
|
|
11
|
+
"Do NOT rewrite non-install pip subcommands such as pip list, pip show, pip freeze, pip uninstall, pip check, or pip config.",
|
|
12
|
+
"Do NOT rewrite commands that use other package managers such as npm install, bun install, pnpm install, cargo install, apt install, or brew install.",
|
|
13
|
+
"The mod must load without errors."
|
|
14
|
+
],
|
|
15
|
+
"candidateDiversityHints": [
|
|
16
|
+
"Use a conservative command parser or regex that only rewrites pip install and python -m pip install forms.",
|
|
17
|
+
"Handle pip install at command boundaries and after simple shell operators like &&, ||, and ; if possible.",
|
|
18
|
+
"Keep the turn_start reminder concise and specific; the deterministic tool_start assertions are the source of truth."
|
|
19
|
+
],
|
|
20
|
+
"modApiHints": [
|
|
21
|
+
"The mod runtime accepts TypeScript files in LETTA_MODS_DIR and calls export function activate(letta) or a default export.",
|
|
22
|
+
"letta.events.on(\"turn_start\", handler) receives event.input (an array of messages). Append a separate { type: \"message\", role: \"system\", content: reminder } object; do not concatenate onto existing content because it may be structured parts.",
|
|
23
|
+
"letta.events.on(\"tool_start\", handler) receives event.toolName, event.args, event.toolCallId, and event.conversationId.",
|
|
24
|
+
"The Bash tool is named \"Bash\" and its command argument is event.args.command (a string).",
|
|
25
|
+
"To rewrite args, return { args: { ...event.args, command: rewrittenCommand } } from the tool_start handler.",
|
|
26
|
+
"Guard event registration behind letta.capabilities.events.turns and letta.capabilities.events.tools checks.",
|
|
27
|
+
"Avoid fragile generated regex strings with embedded quote characters; simple string matching/splitting is fine. The candidate must be syntactically valid TypeScript."
|
|
28
|
+
],
|
|
29
|
+
"examples": [
|
|
30
|
+
{
|
|
31
|
+
"input": "Bash tool with command=\"pip install requests\"",
|
|
32
|
+
"expected": "Rewritten to command=\"uv pip install requests\""
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"input": "Bash tool with command=\"python -m pip install --upgrade numpy\"",
|
|
36
|
+
"expected": "Rewritten to command=\"uv pip install --upgrade numpy\""
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"input": "Bash tool with command=\"pip list\"",
|
|
40
|
+
"expected": "Not rewritten \u2014 pip list is not an install command"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"input": "Bash tool with command=\"npm install express\"",
|
|
44
|
+
"expected": "Not rewritten \u2014 npm is not pip"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"input": "Bash tool with command=\"pip install -r requirements.txt && echo done\"",
|
|
48
|
+
"expected": "Rewritten to command=\"uv pip install -r requirements.txt && echo done\""
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"evaluation": {
|
|
52
|
+
"scenarios": [
|
|
53
|
+
{
|
|
54
|
+
"name": "mod-loads",
|
|
55
|
+
"assertions": [
|
|
56
|
+
{
|
|
57
|
+
"type": "mod_loads",
|
|
58
|
+
"expectedLoadedCount": 1
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "turn-start-reminder",
|
|
64
|
+
"assertions": [
|
|
65
|
+
{
|
|
66
|
+
"type": "turn_start_injects_message",
|
|
67
|
+
"role": "system",
|
|
68
|
+
"contains": ["uv pip install", "pip install"],
|
|
69
|
+
"input": [
|
|
70
|
+
{
|
|
71
|
+
"type": "message",
|
|
72
|
+
"role": "user",
|
|
73
|
+
"content": "Install the Python requests library."
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"name": "single-package-tool-rewrite",
|
|
81
|
+
"assertions": [
|
|
82
|
+
{
|
|
83
|
+
"type": "tool_start_rewrites_args",
|
|
84
|
+
"toolName": "Bash",
|
|
85
|
+
"args": {
|
|
86
|
+
"command": "pip install --dry-run requests"
|
|
87
|
+
},
|
|
88
|
+
"expectArgs": {
|
|
89
|
+
"command": "uv pip install --dry-run requests"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "python-module-tool-rewrite",
|
|
96
|
+
"assertions": [
|
|
97
|
+
{
|
|
98
|
+
"type": "tool_start_rewrites_args",
|
|
99
|
+
"toolName": "Bash",
|
|
100
|
+
"args": {
|
|
101
|
+
"command": "python -m pip install --dry-run --upgrade numpy"
|
|
102
|
+
},
|
|
103
|
+
"expectArgs": {
|
|
104
|
+
"command": "uv pip install --dry-run --upgrade numpy"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"type": "tool_start_rewrites_args",
|
|
109
|
+
"toolName": "Bash",
|
|
110
|
+
"args": {
|
|
111
|
+
"command": "python3 -m pip install --dry-run --upgrade numpy"
|
|
112
|
+
},
|
|
113
|
+
"expectArgs": {
|
|
114
|
+
"command": "uv pip install --dry-run --upgrade numpy"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"name": "multiple-packages-tool-rewrite",
|
|
121
|
+
"assertions": [
|
|
122
|
+
{
|
|
123
|
+
"type": "tool_start_rewrites_args",
|
|
124
|
+
"toolName": "Bash",
|
|
125
|
+
"args": {
|
|
126
|
+
"command": "pip install --dry-run fastapi uvicorn"
|
|
127
|
+
},
|
|
128
|
+
"expectArgs": {
|
|
129
|
+
"command": "uv pip install --dry-run fastapi uvicorn"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"name": "shell-operator-tool-rewrite",
|
|
136
|
+
"assertions": [
|
|
137
|
+
{
|
|
138
|
+
"type": "tool_start_rewrites_args",
|
|
139
|
+
"toolName": "Bash",
|
|
140
|
+
"args": {
|
|
141
|
+
"command": "pip install -r requirements.txt && echo done"
|
|
142
|
+
},
|
|
143
|
+
"expectArgs": {
|
|
144
|
+
"command": "uv pip install -r requirements.txt && echo done"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"name": "negative-control-pip-list-unchanged",
|
|
151
|
+
"assertions": [
|
|
152
|
+
{
|
|
153
|
+
"type": "tool_start_preserves_args",
|
|
154
|
+
"toolName": "Bash",
|
|
155
|
+
"args": {
|
|
156
|
+
"command": "pip list"
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"name": "negative-control-npm-unchanged",
|
|
163
|
+
"assertions": [
|
|
164
|
+
{
|
|
165
|
+
"type": "tool_start_preserves_args",
|
|
166
|
+
"toolName": "Bash",
|
|
167
|
+
"args": {
|
|
168
|
+
"command": "npm install --dry-run --ignore-scripts --package-lock=false lodash"
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"name": "negative-control-brew-unchanged",
|
|
175
|
+
"assertions": [
|
|
176
|
+
{
|
|
177
|
+
"type": "tool_start_preserves_args",
|
|
178
|
+
"toolName": "Bash",
|
|
179
|
+
"args": {
|
|
180
|
+
"command": "brew install wget"
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"name": "negative-control-cargo-unchanged",
|
|
187
|
+
"assertions": [
|
|
188
|
+
{
|
|
189
|
+
"type": "tool_start_preserves_args",
|
|
190
|
+
"toolName": "Bash",
|
|
191
|
+
"args": {
|
|
192
|
+
"command": "cargo install ripgrep"
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
]
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
}
|