@letta-ai/letta-code 0.27.20 → 0.27.22
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/agent-presets.js +3768 -0
- package/dist/agent-presets.js.map +17 -0
- package/dist/types/agent/agent-tags.d.ts +19 -0
- package/dist/types/agent/agent-tags.d.ts.map +1 -0
- package/dist/types/agent/create-agent-request.d.ts +55 -0
- package/dist/types/agent/create-agent-request.d.ts.map +1 -0
- package/dist/types/agent/memory-constants.d.ts +2 -0
- package/dist/types/agent/memory-constants.d.ts.map +1 -0
- package/dist/types/agent/memory.d.ts +29 -0
- package/dist/types/agent/memory.d.ts.map +1 -0
- package/dist/types/agent/model-catalog.d.ts +362 -0
- package/dist/types/agent/model-catalog.d.ts.map +1 -0
- package/dist/types/agent/personality-presets.d.ts +64 -0
- package/dist/types/agent/personality-presets.d.ts.map +1 -0
- package/dist/types/agent/prompt-assets.d.ts +32 -0
- package/dist/types/agent/prompt-assets.d.ts.map +1 -0
- package/dist/types/agent-presets.d.ts +16 -0
- package/dist/types/agent-presets.d.ts.map +1 -0
- package/dist/types/constants.d.ts +53 -0
- package/dist/types/constants.d.ts.map +1 -0
- package/dist/types/types/protocol_v2.d.ts +3 -1
- package/dist/types/types/protocol_v2.d.ts.map +1 -1
- package/letta.js +2029 -3395
- package/package.json +23 -1
- package/scripts/codex-watch/agent-watch.ts +186 -0
- package/scripts/codex-watch/check-release.ts +18 -316
- package/scripts/codex-watch/github.ts +121 -0
- package/scripts/codex-watch/release-analysis.ts +288 -0
- package/scripts/codex-watch/tracker.test.ts +127 -0
- package/scripts/codex-watch/tracker.ts +238 -0
- package/scripts/codex-watch/update-tracker.ts +131 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import type { Verdict } from "./diff-models-json.ts";
|
|
2
|
+
import type { CodexWatchAnalysis } from "./release-analysis.ts";
|
|
3
|
+
|
|
4
|
+
const STATE_START = "<!-- codex-agent-watch-state";
|
|
5
|
+
const STATE_END = "-->";
|
|
6
|
+
const HIDDEN_STATE_LIMIT = 50;
|
|
7
|
+
const VISIBLE_INTERESTING_LIMIT = 20;
|
|
8
|
+
|
|
9
|
+
export type TrackerOutcome =
|
|
10
|
+
| "recorded_noop"
|
|
11
|
+
| "no_local_impact"
|
|
12
|
+
| "pr_created"
|
|
13
|
+
| "needs_human_review"
|
|
14
|
+
| "error";
|
|
15
|
+
|
|
16
|
+
export interface TrackerEntry {
|
|
17
|
+
tag: string;
|
|
18
|
+
previous_tag: string;
|
|
19
|
+
verdict: Verdict;
|
|
20
|
+
outcome: TrackerOutcome;
|
|
21
|
+
pr_url: string | null;
|
|
22
|
+
notes: string;
|
|
23
|
+
processed_at: string;
|
|
24
|
+
compare_url: string;
|
|
25
|
+
workflow_run_url: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface TrackerState {
|
|
29
|
+
last_checked_tag: string | null;
|
|
30
|
+
last_checked_at: string | null;
|
|
31
|
+
processed: TrackerEntry[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface RecordAnalysisOptions {
|
|
35
|
+
analysis: CodexWatchAnalysis;
|
|
36
|
+
outcome: TrackerOutcome;
|
|
37
|
+
notes: string;
|
|
38
|
+
prUrl?: string | null;
|
|
39
|
+
processedAt?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function emptyTrackerState(): TrackerState {
|
|
43
|
+
return {
|
|
44
|
+
last_checked_tag: null,
|
|
45
|
+
last_checked_at: null,
|
|
46
|
+
processed: [],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function parseTrackerState(body: string): TrackerState {
|
|
51
|
+
const start = body.indexOf(STATE_START);
|
|
52
|
+
if (start === -1) return emptyTrackerState();
|
|
53
|
+
|
|
54
|
+
const jsonStart = start + STATE_START.length;
|
|
55
|
+
const end = body.indexOf(STATE_END, jsonStart);
|
|
56
|
+
if (end === -1) return emptyTrackerState();
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
return normalizeState(JSON.parse(body.slice(jsonStart, end).trim()));
|
|
60
|
+
} catch {
|
|
61
|
+
return emptyTrackerState();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function hasProcessedTag(state: TrackerState, tag: string): boolean {
|
|
66
|
+
return state.processed.some((entry) => entry.tag === tag);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function recordAnalysis(
|
|
70
|
+
state: TrackerState,
|
|
71
|
+
options: RecordAnalysisOptions,
|
|
72
|
+
): TrackerState {
|
|
73
|
+
const processedAt = options.processedAt ?? new Date().toISOString();
|
|
74
|
+
return upsertTrackerEntry(state, {
|
|
75
|
+
tag: options.analysis.current_tag,
|
|
76
|
+
previous_tag: options.analysis.previous_tag,
|
|
77
|
+
verdict: options.analysis.verdict,
|
|
78
|
+
outcome: options.outcome,
|
|
79
|
+
pr_url: options.prUrl ?? null,
|
|
80
|
+
notes: options.notes,
|
|
81
|
+
processed_at: processedAt,
|
|
82
|
+
compare_url: options.analysis.compare_url,
|
|
83
|
+
workflow_run_url: options.analysis.workflow_run_url,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function upsertTrackerEntry(
|
|
88
|
+
state: TrackerState,
|
|
89
|
+
entry: TrackerEntry,
|
|
90
|
+
): TrackerState {
|
|
91
|
+
const processed = [
|
|
92
|
+
entry,
|
|
93
|
+
...state.processed.filter((existing) => existing.tag !== entry.tag),
|
|
94
|
+
].slice(0, HIDDEN_STATE_LIMIT);
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
last_checked_tag: entry.tag,
|
|
98
|
+
last_checked_at: entry.processed_at,
|
|
99
|
+
processed,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function renderTrackerBody(state: TrackerState): string {
|
|
104
|
+
const normalized = normalizeState(state);
|
|
105
|
+
const parts: string[] = [
|
|
106
|
+
"Central tracker for the Amelia-driven Codex upstream drift watch experiment.",
|
|
107
|
+
"",
|
|
108
|
+
"The legacy per-release `codex-release-watch.yml` issue workflow is still enabled as the baseline while this tracker bakes off the new automation path.",
|
|
109
|
+
"",
|
|
110
|
+
renderLastChecked(normalized),
|
|
111
|
+
"",
|
|
112
|
+
"## Recent actionable releases",
|
|
113
|
+
"",
|
|
114
|
+
renderInterestingTable(normalized),
|
|
115
|
+
"",
|
|
116
|
+
"## Hidden state",
|
|
117
|
+
"",
|
|
118
|
+
"The workflow uses the hidden JSON block below for dedupe and recent history.",
|
|
119
|
+
"",
|
|
120
|
+
serializeTrackerState(normalized),
|
|
121
|
+
];
|
|
122
|
+
return `${parts.join("\n")}\n`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function serializeTrackerState(state: TrackerState): string {
|
|
126
|
+
const normalized = normalizeState(state);
|
|
127
|
+
return `${STATE_START}\n${JSON.stringify(normalized, null, 2)}\n${STATE_END}`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function isInterestingEntry(entry: TrackerEntry): boolean {
|
|
131
|
+
return entry.verdict !== "no-op" || entry.outcome !== "recorded_noop";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function renderLastChecked(state: TrackerState): string {
|
|
135
|
+
if (!state.last_checked_tag || !state.last_checked_at) {
|
|
136
|
+
return "_Last checked: never._";
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const latest = state.processed.find(
|
|
140
|
+
(entry) => entry.tag === state.last_checked_tag,
|
|
141
|
+
);
|
|
142
|
+
const suffix = latest ? `, ${statusSummary(latest)}.` : ".";
|
|
143
|
+
return `_Last checked: ${state.last_checked_tag} at ${state.last_checked_at}${suffix}_`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function renderInterestingTable(state: TrackerState): string {
|
|
147
|
+
const interesting = state.processed
|
|
148
|
+
.filter(isInterestingEntry)
|
|
149
|
+
.slice(0, VISIBLE_INTERESTING_LIMIT);
|
|
150
|
+
|
|
151
|
+
if (interesting.length === 0) {
|
|
152
|
+
return "_No actionable releases recorded yet._";
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const rows = [
|
|
156
|
+
"| Release | Verdict | Outcome | PR | Notes |",
|
|
157
|
+
"|---|---|---|---|---|",
|
|
158
|
+
];
|
|
159
|
+
for (const entry of interesting) {
|
|
160
|
+
rows.push(
|
|
161
|
+
`| [${escapeTable(entry.tag)}](${entry.compare_url}) | ${escapeTable(entry.verdict)} | ${escapeTable(entry.outcome)} | ${renderPr(entry.pr_url)} | ${escapeTable(entry.notes)} |`,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return rows.join("\n");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function statusSummary(entry: TrackerEntry): string {
|
|
168
|
+
if (entry.outcome === "recorded_noop") return "no watched changes";
|
|
169
|
+
if (entry.outcome === "pr_created" && entry.pr_url) {
|
|
170
|
+
return `PR created: ${entry.pr_url}`;
|
|
171
|
+
}
|
|
172
|
+
return entry.notes || entry.outcome;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function renderPr(prUrl: string | null): string {
|
|
176
|
+
return prUrl ? `[PR](${prUrl})` : "-";
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function escapeTable(value: string): string {
|
|
180
|
+
return value.replaceAll("|", "\\|").replaceAll("\n", " ");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function normalizeState(value: unknown): TrackerState {
|
|
184
|
+
if (!isRecord(value)) return emptyTrackerState();
|
|
185
|
+
|
|
186
|
+
const processed = Array.isArray(value.processed)
|
|
187
|
+
? value.processed.filter(isTrackerEntry).slice(0, HIDDEN_STATE_LIMIT)
|
|
188
|
+
: [];
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
last_checked_tag:
|
|
192
|
+
typeof value.last_checked_tag === "string"
|
|
193
|
+
? value.last_checked_tag
|
|
194
|
+
: null,
|
|
195
|
+
last_checked_at:
|
|
196
|
+
typeof value.last_checked_at === "string" ? value.last_checked_at : null,
|
|
197
|
+
processed,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function isTrackerEntry(value: unknown): value is TrackerEntry {
|
|
202
|
+
if (!isRecord(value)) return false;
|
|
203
|
+
return (
|
|
204
|
+
typeof value.tag === "string" &&
|
|
205
|
+
typeof value.previous_tag === "string" &&
|
|
206
|
+
isVerdict(value.verdict) &&
|
|
207
|
+
isOutcome(value.outcome) &&
|
|
208
|
+
(typeof value.pr_url === "string" || value.pr_url === null) &&
|
|
209
|
+
typeof value.notes === "string" &&
|
|
210
|
+
typeof value.processed_at === "string" &&
|
|
211
|
+
typeof value.compare_url === "string" &&
|
|
212
|
+
typeof value.workflow_run_url === "string"
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function isVerdict(value: unknown): value is Verdict {
|
|
217
|
+
return (
|
|
218
|
+
value === "no-op" ||
|
|
219
|
+
value === "prompt-only update" ||
|
|
220
|
+
value === "tool-schema update needed" ||
|
|
221
|
+
value === "tool-surface review needed" ||
|
|
222
|
+
value === "manual review required"
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function isOutcome(value: unknown): value is TrackerOutcome {
|
|
227
|
+
return (
|
|
228
|
+
value === "recorded_noop" ||
|
|
229
|
+
value === "no_local_impact" ||
|
|
230
|
+
value === "pr_created" ||
|
|
231
|
+
value === "needs_human_review" ||
|
|
232
|
+
value === "error"
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
237
|
+
return typeof value === "object" && value !== null;
|
|
238
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Records an Amelia Codex watch outcome in the central tracker issue.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* bun scripts/codex-watch/update-tracker.ts --tracker-issue 123 --analysis-file /tmp/analysis.json --outcome no_local_impact --notes "upstream-only"
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { readFileSync } from "node:fs";
|
|
10
|
+
import { editIssueBody, getIssueBody } from "./github.ts";
|
|
11
|
+
import {
|
|
12
|
+
type CodexWatchAnalysis,
|
|
13
|
+
DEFAULT_TARGET_REPO,
|
|
14
|
+
} from "./release-analysis.ts";
|
|
15
|
+
import {
|
|
16
|
+
parseTrackerState,
|
|
17
|
+
recordAnalysis,
|
|
18
|
+
renderTrackerBody,
|
|
19
|
+
type TrackerOutcome,
|
|
20
|
+
} from "./tracker.ts";
|
|
21
|
+
|
|
22
|
+
interface Args {
|
|
23
|
+
repo: string;
|
|
24
|
+
trackerIssue: number | null;
|
|
25
|
+
analysisFile: string | null;
|
|
26
|
+
outcome: TrackerOutcome | null;
|
|
27
|
+
notes: string;
|
|
28
|
+
prUrl: string | null;
|
|
29
|
+
dryRun: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function parseArgs(argv: string[]): Args {
|
|
33
|
+
const args: Args = {
|
|
34
|
+
repo: DEFAULT_TARGET_REPO,
|
|
35
|
+
trackerIssue: null,
|
|
36
|
+
analysisFile: null,
|
|
37
|
+
outcome: null,
|
|
38
|
+
notes: "",
|
|
39
|
+
prUrl: null,
|
|
40
|
+
dryRun: false,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
for (let i = 0; i < argv.length; i++) {
|
|
44
|
+
const a = argv[i];
|
|
45
|
+
if (a === "--repo") args.repo = argv[++i] ?? args.repo;
|
|
46
|
+
else if (a === "--tracker-issue") {
|
|
47
|
+
args.trackerIssue = Number(argv[++i]);
|
|
48
|
+
} else if (a === "--analysis-file") args.analysisFile = argv[++i] ?? null;
|
|
49
|
+
else if (a === "--outcome") args.outcome = parseOutcome(argv[++i]);
|
|
50
|
+
else if (a === "--notes") args.notes = argv[++i] ?? "";
|
|
51
|
+
else if (a === "--pr-url") args.prUrl = argv[++i] ?? null;
|
|
52
|
+
else if (a === "--dry-run") args.dryRun = true;
|
|
53
|
+
else if (a === "--help" || a === "-h") {
|
|
54
|
+
console.log(
|
|
55
|
+
"Usage: bun scripts/codex-watch/update-tracker.ts --tracker-issue ISSUE --analysis-file FILE --outcome OUTCOME [--notes TEXT] [--pr-url URL] [--repo OWNER/REPO] [--dry-run]",
|
|
56
|
+
);
|
|
57
|
+
process.exit(0);
|
|
58
|
+
} else {
|
|
59
|
+
throw new Error(`Unknown argument: ${a}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!args.trackerIssue || Number.isNaN(args.trackerIssue)) {
|
|
64
|
+
throw new Error("--tracker-issue is required");
|
|
65
|
+
}
|
|
66
|
+
if (!args.analysisFile) throw new Error("--analysis-file is required");
|
|
67
|
+
if (!args.outcome) throw new Error("--outcome is required");
|
|
68
|
+
if (args.outcome === "pr_created" && !args.prUrl) {
|
|
69
|
+
throw new Error("--pr-url is required when --outcome pr_created");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return args;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function parseOutcome(value: string | undefined): TrackerOutcome {
|
|
76
|
+
if (
|
|
77
|
+
value === "recorded_noop" ||
|
|
78
|
+
value === "no_local_impact" ||
|
|
79
|
+
value === "pr_created" ||
|
|
80
|
+
value === "needs_human_review" ||
|
|
81
|
+
value === "error"
|
|
82
|
+
) {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
throw new Error(`Unknown outcome: ${value}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function readAnalysis(path: string): CodexWatchAnalysis {
|
|
89
|
+
return JSON.parse(readFileSync(path, "utf8")) as CodexWatchAnalysis;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function main() {
|
|
93
|
+
const args = parseArgs(process.argv.slice(2));
|
|
94
|
+
const analysis = readAnalysis(args.analysisFile as string);
|
|
95
|
+
const body = getIssueBody(args.repo, args.trackerIssue as number);
|
|
96
|
+
const state = parseTrackerState(body);
|
|
97
|
+
const next = recordAnalysis(state, {
|
|
98
|
+
analysis,
|
|
99
|
+
outcome: args.outcome as TrackerOutcome,
|
|
100
|
+
notes: args.notes || defaultNotes(args.outcome as TrackerOutcome),
|
|
101
|
+
prUrl: args.prUrl,
|
|
102
|
+
});
|
|
103
|
+
const nextBody = renderTrackerBody(next);
|
|
104
|
+
|
|
105
|
+
if (args.dryRun) {
|
|
106
|
+
console.log(nextBody);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
editIssueBody(args.repo, args.trackerIssue as number, nextBody);
|
|
111
|
+
console.log(
|
|
112
|
+
`Recorded ${analysis.current_tag} as ${args.outcome} in #${args.trackerIssue}`,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function defaultNotes(outcome: TrackerOutcome): string {
|
|
117
|
+
switch (outcome) {
|
|
118
|
+
case "recorded_noop":
|
|
119
|
+
return "no watched tool-surface changes detected";
|
|
120
|
+
case "no_local_impact":
|
|
121
|
+
return "reviewed; no local Letta Code mirror impact";
|
|
122
|
+
case "pr_created":
|
|
123
|
+
return "opened PR for local mirror update";
|
|
124
|
+
case "needs_human_review":
|
|
125
|
+
return "needs human review";
|
|
126
|
+
case "error":
|
|
127
|
+
return "automation hit an error";
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
main();
|