@letta-ai/letta-code 0.14.4 → 0.14.6
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/letta.js +6371 -4834
- package/package.json +1 -1
- package/skills/acquiring-skills/SKILL.md +9 -5
- package/skills/defragmenting-memory/SKILL.md +4 -5
- package/skills/finding-agents/SKILL.md +12 -12
- package/skills/messaging-agents/SKILL.md +19 -19
- package/skills/migrating-memory/SKILL.md +47 -81
- package/skills/searching-messages/SKILL.md +14 -16
- package/skills/syncing-memory-filesystem/SKILL.md +27 -46
- package/skills/finding-agents/scripts/find-agents.ts +0 -177
- package/skills/messaging-agents/scripts/continue-conversation.ts +0 -226
- package/skills/messaging-agents/scripts/start-conversation.ts +0 -229
- package/skills/migrating-memory/scripts/attach-block.ts +0 -230
- package/skills/migrating-memory/scripts/copy-block.ts +0 -261
- package/skills/migrating-memory/scripts/get-agent-blocks.ts +0 -103
- package/skills/searching-messages/scripts/get-messages.ts +0 -230
- package/skills/searching-messages/scripts/search-messages.ts +0 -200
- package/skills/syncing-memory-filesystem/scripts/lib/frontmatter.ts +0 -47
- package/skills/syncing-memory-filesystem/scripts/memfs-diff.ts +0 -430
- package/skills/syncing-memory-filesystem/scripts/memfs-resolve.ts +0 -506
- package/skills/syncing-memory-filesystem/scripts/memfs-status.ts +0 -391
|
@@ -9,82 +9,63 @@ When memFS is enabled, your memory blocks are mirrored as `.md` files on disk at
|
|
|
9
9
|
|
|
10
10
|
**Conflicts** occur when both the file and the block are modified since the last sync (e.g., user edits a file in their editor while the block is also updated manually by the user via the API). Non-conflicting changes (only one side changed) are resolved automatically during the next sync.
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## CLI Commands
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Use the built-in CLI subcommands. They use the same auth flow as the CLI
|
|
15
|
+
(OAuth/keychain + refresh), and default to `LETTA_AGENT_ID` when available.
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
```bash
|
|
18
|
+
letta memfs status --agent <agent-id>
|
|
19
|
+
letta memfs diff --agent <agent-id>
|
|
20
|
+
letta memfs resolve --agent <agent-id> --resolutions '<JSON>'
|
|
21
|
+
```
|
|
17
22
|
|
|
23
|
+
Auth overrides (optional):
|
|
18
24
|
```bash
|
|
19
|
-
|
|
25
|
+
LETTA_API_KEY=... letta memfs status --agent <agent-id>
|
|
26
|
+
LETTA_BASE_URL=http://localhost:8283 LETTA_API_KEY=... letta memfs status --agent <agent-id>
|
|
20
27
|
```
|
|
21
28
|
|
|
22
|
-
**Output**: JSON
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- `
|
|
29
|
+
**Output**: JSON only.
|
|
30
|
+
|
|
31
|
+
**Status output fields**:
|
|
32
|
+
- `conflicts` — blocks where both file and block changed
|
|
33
|
+
- `pendingFromFile` — file changed, block didn’t (auto-resolved on sync)
|
|
34
|
+
- `pendingFromBlock` — block changed, file didn’t (auto-resolved on sync)
|
|
26
35
|
- `newFiles` — files without corresponding blocks
|
|
27
36
|
- `newBlocks` — blocks without corresponding files
|
|
37
|
+
- `locationMismatches` — file location doesn’t match attachment state
|
|
28
38
|
- `isClean` — true if everything is in sync
|
|
29
39
|
- `lastSync` — timestamp of last sync
|
|
30
40
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
### 2. `memfs-diff.ts` — View conflict details (like `git diff`)
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
npx tsx <SKILL_DIR>/scripts/memfs-diff.ts $LETTA_AGENT_ID
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
**Output**: Writes a formatted markdown diff file showing both the file version and block version of each conflicting label. The path to the diff file is printed to stdout.
|
|
40
|
-
|
|
41
|
-
Use the `Read` tool to review the diff file content.
|
|
42
|
-
|
|
43
|
-
### 3. `memfs-resolve.ts` — Resolve conflicts (like `git merge`)
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
npx tsx <SKILL_DIR>/scripts/memfs-resolve.ts $LETTA_AGENT_ID --resolutions '<JSON>'
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
**Arguments**:
|
|
50
|
-
- `--resolutions` — JSON array of resolution objects
|
|
51
|
-
|
|
52
|
-
**Resolution format**:
|
|
53
|
-
```json
|
|
54
|
-
[
|
|
55
|
-
{"label": "persona/soul", "resolution": "block"},
|
|
56
|
-
{"label": "human/prefs", "resolution": "file"}
|
|
57
|
-
]
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
**Resolution options**:
|
|
61
|
-
- `"file"` — Overwrite the memory block with the file contents
|
|
62
|
-
- `"block"` — Overwrite the file with the memory block contents
|
|
41
|
+
**Diff output**:
|
|
42
|
+
- Writes a markdown diff file and returns `{ diffPath, conflicts, metadataOnly }`
|
|
63
43
|
|
|
64
|
-
|
|
44
|
+
**Resolve output**:
|
|
45
|
+
- Returns the sync result from `syncMemoryFilesystem` (created/updated/deleted blocks/files, conflicts).
|
|
65
46
|
|
|
66
47
|
## Typical Workflow
|
|
67
48
|
|
|
68
49
|
1. You receive a system reminder about memFS conflicts
|
|
69
|
-
2. Run `memfs
|
|
50
|
+
2. Run `letta memfs diff` to see the full content of both sides
|
|
70
51
|
3. Read the diff file to understand the changes
|
|
71
52
|
4. Decide for each conflict: keep the file version or the block version
|
|
72
|
-
5. Run `memfs
|
|
53
|
+
5. Run `letta memfs resolve` with all resolutions at once
|
|
73
54
|
|
|
74
55
|
## Example
|
|
75
56
|
|
|
76
57
|
```bash
|
|
77
58
|
# Step 1: Check status (optional — the system reminder already tells you about conflicts)
|
|
78
|
-
|
|
59
|
+
letta memfs status --agent $LETTA_AGENT_ID
|
|
79
60
|
|
|
80
61
|
# Step 2: View the diffs
|
|
81
|
-
|
|
62
|
+
letta memfs diff --agent $LETTA_AGENT_ID
|
|
82
63
|
# Output: "Diff (2 conflicts) written to: /path/to/diff.md"
|
|
83
64
|
|
|
84
65
|
# Step 3: Read the diff file (use Read tool on the path from step 2)
|
|
85
66
|
|
|
86
67
|
# Step 4: Resolve all conflicts
|
|
87
|
-
|
|
68
|
+
letta memfs resolve --agent $LETTA_AGENT_ID --resolutions '[{"label":"persona/soul","resolution":"block"},{"label":"human/prefs","resolution":"file"}]'
|
|
88
69
|
```
|
|
89
70
|
|
|
90
71
|
## How Conflicts Arise
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env npx tsx
|
|
2
|
-
/**
|
|
3
|
-
* Find Agents - Search for agents with various filters
|
|
4
|
-
*
|
|
5
|
-
* This script is standalone and can be run outside the CLI process.
|
|
6
|
-
* It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* npx tsx find-agents.ts [options]
|
|
10
|
-
*
|
|
11
|
-
* Options:
|
|
12
|
-
* --name <name> Exact name match
|
|
13
|
-
* --query <text> Fuzzy search by name
|
|
14
|
-
* --tags <tag1,tag2> Filter by tags (comma-separated)
|
|
15
|
-
* --match-all-tags Require ALL tags (default: ANY)
|
|
16
|
-
* --include-blocks Include agent.blocks in response
|
|
17
|
-
* --limit <n> Max results (default: 20)
|
|
18
|
-
*
|
|
19
|
-
* Output:
|
|
20
|
-
* Raw API response from GET /v1/agents
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
import { readFileSync } from "node:fs";
|
|
24
|
-
import { createRequire } from "node:module";
|
|
25
|
-
import { homedir } from "node:os";
|
|
26
|
-
import { join } from "node:path";
|
|
27
|
-
|
|
28
|
-
// Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
|
|
29
|
-
// (ES module imports don't respect NODE_PATH, but require does)
|
|
30
|
-
const require = createRequire(import.meta.url);
|
|
31
|
-
const Letta = require("@letta-ai/letta-client")
|
|
32
|
-
.default as typeof import("@letta-ai/letta-client").default;
|
|
33
|
-
type LettaClient = InstanceType<typeof Letta>;
|
|
34
|
-
|
|
35
|
-
interface FindAgentsOptions {
|
|
36
|
-
name?: string;
|
|
37
|
-
query?: string;
|
|
38
|
-
tags?: string[];
|
|
39
|
-
matchAllTags?: boolean;
|
|
40
|
-
includeBlocks?: boolean;
|
|
41
|
-
limit?: number;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Get API key from env var or settings file
|
|
46
|
-
*/
|
|
47
|
-
function getApiKey(): string {
|
|
48
|
-
// First check env var (set by CLI's getShellEnv)
|
|
49
|
-
if (process.env.LETTA_API_KEY) {
|
|
50
|
-
return process.env.LETTA_API_KEY;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Fall back to settings file
|
|
54
|
-
const settingsPath = join(homedir(), ".letta", "settings.json");
|
|
55
|
-
try {
|
|
56
|
-
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
57
|
-
if (settings.env?.LETTA_API_KEY) {
|
|
58
|
-
return settings.env.LETTA_API_KEY;
|
|
59
|
-
}
|
|
60
|
-
} catch {
|
|
61
|
-
// Settings file doesn't exist or is invalid
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
throw new Error(
|
|
65
|
-
"No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Create a Letta client with auth from env/settings
|
|
71
|
-
*/
|
|
72
|
-
function createClient(): LettaClient {
|
|
73
|
-
return new Letta({ apiKey: getApiKey() });
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Find agents matching the given criteria
|
|
78
|
-
* @param client - Letta client instance
|
|
79
|
-
* @param options - Search options
|
|
80
|
-
* @returns Array of agent objects from the API
|
|
81
|
-
*/
|
|
82
|
-
export async function findAgents(
|
|
83
|
-
client: LettaClient,
|
|
84
|
-
options: FindAgentsOptions = {},
|
|
85
|
-
): Promise<Awaited<ReturnType<typeof client.agents.list>>> {
|
|
86
|
-
const params: Parameters<typeof client.agents.list>[0] = {
|
|
87
|
-
limit: options.limit ?? 20,
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
if (options.name) {
|
|
91
|
-
params.name = options.name;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (options.query) {
|
|
95
|
-
params.query_text = options.query;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (options.tags && options.tags.length > 0) {
|
|
99
|
-
params.tags = options.tags;
|
|
100
|
-
if (options.matchAllTags) {
|
|
101
|
-
params.match_all_tags = true;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (options.includeBlocks) {
|
|
106
|
-
params.include = ["agent.blocks"];
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return await client.agents.list(params);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function parseArgs(args: string[]): FindAgentsOptions {
|
|
113
|
-
const options: FindAgentsOptions = {};
|
|
114
|
-
|
|
115
|
-
const nameIndex = args.indexOf("--name");
|
|
116
|
-
if (nameIndex !== -1 && nameIndex + 1 < args.length) {
|
|
117
|
-
options.name = args[nameIndex + 1];
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const queryIndex = args.indexOf("--query");
|
|
121
|
-
if (queryIndex !== -1 && queryIndex + 1 < args.length) {
|
|
122
|
-
options.query = args[queryIndex + 1];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const tagsIndex = args.indexOf("--tags");
|
|
126
|
-
if (tagsIndex !== -1 && tagsIndex + 1 < args.length) {
|
|
127
|
-
options.tags = args[tagsIndex + 1]?.split(",").map((t) => t.trim());
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (args.includes("--match-all-tags")) {
|
|
131
|
-
options.matchAllTags = true;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (args.includes("--include-blocks")) {
|
|
135
|
-
options.includeBlocks = true;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const limitIndex = args.indexOf("--limit");
|
|
139
|
-
if (limitIndex !== -1 && limitIndex + 1 < args.length) {
|
|
140
|
-
const limit = Number.parseInt(args[limitIndex + 1] as string, 10);
|
|
141
|
-
if (!Number.isNaN(limit)) {
|
|
142
|
-
options.limit = limit;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return options;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// CLI entry point - check if this file is being run directly
|
|
150
|
-
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
151
|
-
if (isMainModule) {
|
|
152
|
-
(async () => {
|
|
153
|
-
try {
|
|
154
|
-
const options = parseArgs(process.argv.slice(2));
|
|
155
|
-
const client = createClient();
|
|
156
|
-
const result = await findAgents(client, options);
|
|
157
|
-
console.log(JSON.stringify(result, null, 2));
|
|
158
|
-
} catch (error) {
|
|
159
|
-
console.error(
|
|
160
|
-
"Error:",
|
|
161
|
-
error instanceof Error ? error.message : String(error),
|
|
162
|
-
);
|
|
163
|
-
console.error(`
|
|
164
|
-
Usage: npx tsx find-agents.ts [options]
|
|
165
|
-
|
|
166
|
-
Options:
|
|
167
|
-
--name <name> Exact name match
|
|
168
|
-
--query <text> Fuzzy search by name
|
|
169
|
-
--tags <tag1,tag2> Filter by tags (comma-separated)
|
|
170
|
-
--match-all-tags Require ALL tags (default: ANY)
|
|
171
|
-
--include-blocks Include agent.blocks in response
|
|
172
|
-
--limit <n> Max results (default: 20)
|
|
173
|
-
`);
|
|
174
|
-
process.exit(1);
|
|
175
|
-
}
|
|
176
|
-
})();
|
|
177
|
-
}
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env npx tsx
|
|
2
|
-
/**
|
|
3
|
-
* Continue Conversation - Send a follow-up message to an existing conversation
|
|
4
|
-
*
|
|
5
|
-
* This script is standalone and can be run outside the CLI process.
|
|
6
|
-
* It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
|
|
7
|
-
* It reads sender agent ID from LETTA_AGENT_ID env var.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* npx tsx continue-conversation.ts --conversation-id <id> --message "<text>"
|
|
11
|
-
*
|
|
12
|
-
* Options:
|
|
13
|
-
* --conversation-id <id> Existing conversation ID (required)
|
|
14
|
-
* --message <text> Message to send (required)
|
|
15
|
-
* --timeout <ms> Max wait time in ms (default: 120000)
|
|
16
|
-
*
|
|
17
|
-
* Output:
|
|
18
|
-
* JSON with conversation_id, response, agent_id, agent_name
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { readFileSync } from "node:fs";
|
|
22
|
-
import { createRequire } from "node:module";
|
|
23
|
-
import { homedir } from "node:os";
|
|
24
|
-
import { join } from "node:path";
|
|
25
|
-
import {
|
|
26
|
-
SYSTEM_REMINDER_CLOSE,
|
|
27
|
-
SYSTEM_REMINDER_OPEN,
|
|
28
|
-
} from "../../../../constants";
|
|
29
|
-
|
|
30
|
-
// Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
|
|
31
|
-
// (ES module imports don't respect NODE_PATH, but require does)
|
|
32
|
-
const require = createRequire(import.meta.url);
|
|
33
|
-
const Letta = require("@letta-ai/letta-client")
|
|
34
|
-
.default as typeof import("@letta-ai/letta-client").default;
|
|
35
|
-
type LettaClient = InstanceType<typeof Letta>;
|
|
36
|
-
|
|
37
|
-
interface ContinueConversationOptions {
|
|
38
|
-
conversationId: string;
|
|
39
|
-
message: string;
|
|
40
|
-
timeout?: number;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
interface ContinueConversationResult {
|
|
44
|
-
conversation_id: string;
|
|
45
|
-
response: string;
|
|
46
|
-
agent_id: string;
|
|
47
|
-
agent_name: string;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Get API key from env var or settings file
|
|
52
|
-
*/
|
|
53
|
-
function getApiKey(): string {
|
|
54
|
-
if (process.env.LETTA_API_KEY) {
|
|
55
|
-
return process.env.LETTA_API_KEY;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const settingsPath = join(homedir(), ".letta", "settings.json");
|
|
59
|
-
try {
|
|
60
|
-
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
61
|
-
if (settings.env?.LETTA_API_KEY) {
|
|
62
|
-
return settings.env.LETTA_API_KEY;
|
|
63
|
-
}
|
|
64
|
-
} catch {
|
|
65
|
-
// Settings file doesn't exist or is invalid
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
throw new Error(
|
|
69
|
-
"No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Get the sender agent ID from env var
|
|
75
|
-
*/
|
|
76
|
-
function getSenderAgentId(): string {
|
|
77
|
-
if (process.env.LETTA_AGENT_ID) {
|
|
78
|
-
return process.env.LETTA_AGENT_ID;
|
|
79
|
-
}
|
|
80
|
-
throw new Error(
|
|
81
|
-
"No LETTA_AGENT_ID found. This script should be run from within a Letta Code session.",
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Create a Letta client with auth from env/settings
|
|
87
|
-
*/
|
|
88
|
-
function createClient(): LettaClient {
|
|
89
|
-
return new Letta({ apiKey: getApiKey() });
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Build the system reminder prefix for the message
|
|
94
|
-
*/
|
|
95
|
-
function buildSystemReminder(
|
|
96
|
-
senderAgentName: string,
|
|
97
|
-
senderAgentId: string,
|
|
98
|
-
): string {
|
|
99
|
-
return `${SYSTEM_REMINDER_OPEN}
|
|
100
|
-
This message is from "${senderAgentName}" (agent ID: ${senderAgentId}), an agent currently running inside the Letta Code CLI (docs.letta.com/letta-code).
|
|
101
|
-
The sender will only see the final message you generate (not tool calls or reasoning).
|
|
102
|
-
If you need to share detailed information, include it in your response text.
|
|
103
|
-
${SYSTEM_REMINDER_CLOSE}
|
|
104
|
-
|
|
105
|
-
`;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Continue an existing conversation by sending a follow-up message
|
|
110
|
-
* @param client - Letta client instance
|
|
111
|
-
* @param options - Options including conversation ID and message
|
|
112
|
-
* @returns Conversation result with response and metadata
|
|
113
|
-
*/
|
|
114
|
-
export async function continueConversation(
|
|
115
|
-
client: LettaClient,
|
|
116
|
-
options: ContinueConversationOptions,
|
|
117
|
-
): Promise<ContinueConversationResult> {
|
|
118
|
-
const { conversationId, message } = options;
|
|
119
|
-
|
|
120
|
-
// 1. Fetch conversation to get agent_id and validate it exists
|
|
121
|
-
const conversation = await client.conversations.retrieve(conversationId);
|
|
122
|
-
|
|
123
|
-
// 2. Fetch target agent to get name
|
|
124
|
-
const targetAgent = await client.agents.retrieve(conversation.agent_id);
|
|
125
|
-
|
|
126
|
-
// 3. Fetch sender agent to get name for system reminder
|
|
127
|
-
const senderAgentId = getSenderAgentId();
|
|
128
|
-
const senderAgent = await client.agents.retrieve(senderAgentId);
|
|
129
|
-
|
|
130
|
-
// 4. Build message with system reminder prefix
|
|
131
|
-
const systemReminder = buildSystemReminder(senderAgent.name, senderAgentId);
|
|
132
|
-
const fullMessage = systemReminder + message;
|
|
133
|
-
|
|
134
|
-
// 5. Send message and consume the stream
|
|
135
|
-
// Note: conversations.messages.create always returns a Stream
|
|
136
|
-
const stream = await client.conversations.messages.create(conversationId, {
|
|
137
|
-
input: fullMessage,
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// 6. Consume stream and extract final assistant message
|
|
141
|
-
let finalResponse = "";
|
|
142
|
-
for await (const chunk of stream) {
|
|
143
|
-
if (chunk.message_type === "assistant_message") {
|
|
144
|
-
// Content can be string or array of content parts
|
|
145
|
-
const content = chunk.content;
|
|
146
|
-
if (typeof content === "string") {
|
|
147
|
-
finalResponse += content;
|
|
148
|
-
} else if (Array.isArray(content)) {
|
|
149
|
-
for (const part of content) {
|
|
150
|
-
if (
|
|
151
|
-
typeof part === "object" &&
|
|
152
|
-
part !== null &&
|
|
153
|
-
"type" in part &&
|
|
154
|
-
part.type === "text" &&
|
|
155
|
-
"text" in part
|
|
156
|
-
) {
|
|
157
|
-
finalResponse += (part as { text: string }).text;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
conversation_id: conversationId,
|
|
166
|
-
response: finalResponse,
|
|
167
|
-
agent_id: targetAgent.id,
|
|
168
|
-
agent_name: targetAgent.name,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function parseArgs(args: string[]): ContinueConversationOptions {
|
|
173
|
-
const conversationIdIndex = args.indexOf("--conversation-id");
|
|
174
|
-
if (conversationIdIndex === -1 || conversationIdIndex + 1 >= args.length) {
|
|
175
|
-
throw new Error(
|
|
176
|
-
"Missing required argument: --conversation-id <conversation-id>",
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
const conversationId = args[conversationIdIndex + 1] as string;
|
|
180
|
-
|
|
181
|
-
const messageIndex = args.indexOf("--message");
|
|
182
|
-
if (messageIndex === -1 || messageIndex + 1 >= args.length) {
|
|
183
|
-
throw new Error("Missing required argument: --message <text>");
|
|
184
|
-
}
|
|
185
|
-
const message = args[messageIndex + 1] as string;
|
|
186
|
-
|
|
187
|
-
const options: ContinueConversationOptions = { conversationId, message };
|
|
188
|
-
|
|
189
|
-
const timeoutIndex = args.indexOf("--timeout");
|
|
190
|
-
if (timeoutIndex !== -1 && timeoutIndex + 1 < args.length) {
|
|
191
|
-
const timeout = Number.parseInt(args[timeoutIndex + 1] as string, 10);
|
|
192
|
-
if (!Number.isNaN(timeout)) {
|
|
193
|
-
options.timeout = timeout;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return options;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// CLI entry point - check if this file is being run directly
|
|
201
|
-
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
202
|
-
if (isMainModule) {
|
|
203
|
-
(async () => {
|
|
204
|
-
try {
|
|
205
|
-
const options = parseArgs(process.argv.slice(2));
|
|
206
|
-
const client = createClient();
|
|
207
|
-
const result = await continueConversation(client, options);
|
|
208
|
-
console.log(JSON.stringify(result, null, 2));
|
|
209
|
-
process.exit(0);
|
|
210
|
-
} catch (error) {
|
|
211
|
-
console.error(
|
|
212
|
-
"Error:",
|
|
213
|
-
error instanceof Error ? error.message : String(error),
|
|
214
|
-
);
|
|
215
|
-
console.error(`
|
|
216
|
-
Usage: npx tsx continue-conversation.ts --conversation-id <id> --message "<text>"
|
|
217
|
-
|
|
218
|
-
Options:
|
|
219
|
-
--conversation-id <id> Existing conversation ID (required)
|
|
220
|
-
--message <text> Message to send (required)
|
|
221
|
-
--timeout <ms> Max wait time in ms (default: 120000)
|
|
222
|
-
`);
|
|
223
|
-
process.exit(1);
|
|
224
|
-
}
|
|
225
|
-
})();
|
|
226
|
-
}
|