Skip to content

Commit df193dd

Browse files
committed
📦 NEW: Pipe and Memory in CLI
1 parent e8ab438 commit df193dd

File tree

19 files changed

+993
-3
lines changed

19 files changed

+993
-3
lines changed

packages/cli/README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,77 @@ Integrate the Langbase Docs MCP server into your IDEs and Claude Desktop.
5757
}
5858
```
5959

60+
61+
## CLI Commands
62+
63+
Get started with the Langbase CLI by running the following command:
64+
65+
```bash
66+
npx @langbase/cli help
67+
```
68+
69+
### Pipe Agent
70+
The CLI provides commands to manage your Langbase pipes.
71+
72+
- Create a new pipe agent
73+
```bash
74+
npx @langbase/cli pipe
75+
```
76+
77+
- Run a pipe agent
78+
```bash
79+
npx @langbase/cli pipe --run
80+
```
81+
82+
- List all pipe agents
83+
```bash
84+
npx @langbase/cli pipe --listPipes
85+
```
86+
87+
- Update a pipe agent
88+
```bash
89+
npx @langbase/cli pipe --update
90+
```
91+
92+
93+
### Memory
94+
The CLI provides commands to manage your Langbase memories.
95+
96+
- Create a new memory
97+
```bash
98+
npx @langbase/cli memory
99+
```
100+
101+
- Upload a document to memory
102+
```bash
103+
npx @langbase/cli memory --upload
104+
```
105+
106+
- List all memories
107+
```bash
108+
npx @langbase/cli memory --listMemories
109+
```
110+
111+
- Retrieve chunks from memory
112+
```bash
113+
npx @langbase/cli memory --retrieve
114+
```
115+
116+
- List all documents in memory
117+
```bash
118+
npx @langbase/cli memory --listDocs
119+
```
120+
121+
- Retry embedding of a document in a memory
122+
```bash
123+
npx @langbase/cli memory --embed
124+
```
125+
126+
- Delete a memory
127+
```bash
128+
npx @langbase/cli memory --delete
129+
```
130+
60131
## Next steps
61132

62133
- Read the [Langbase SDK documentation](https://langbase.com/docs/sdk) for more details

packages/cli/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"@clack/prompts": "^0.7.0",
5252
"@hono/node-server": "^1.13.1",
5353
"@hono/zod-openapi": "^0.16.0",
54+
"@langbase/cli": "^0.1.4",
5455
"@modelcontextprotocol/sdk": "^1.8.0",
5556
"@sindresorhus/slugify": "^2.2.1",
5657
"camelcase": "^8.0.0",
@@ -73,6 +74,7 @@
7374
"hono": "^4.5.11",
7475
"js-tiktoken": "^1.0.14",
7576
"jsdom": "^24.1.0",
77+
"langbase": "^1.1.55",
7678
"log-symbols": "^7.0.0",
7779
"lowdb": "^7.0.1",
7880
"meow": "^13.2.0",
@@ -87,7 +89,8 @@
8789
"uuid": "^10.0.0",
8890
"xlsx": "^0.18.5",
8991
"zod": "^3.23.8",
90-
"zod-error": "^1.5.0"
92+
"zod-error": "^1.5.0",
93+
"zod-validation-error": "^3.3.0"
9194
},
9295
"devDependencies": {
9396
"@langbase/eslint-config": "workspace:*",

packages/cli/src/auth/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,4 @@ export async function auth() {
112112
`Authentication successful. API key is stored in ${envFile}`
113113
)
114114
);
115-
process.exit(0);
116115
}

packages/cli/src/index.ts

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,20 @@ import { auth } from './auth';
33
import { build } from './build';
44
import { deploy } from './deploy';
55
import { docsMcpServer } from './docs-mcp-server';
6+
import { createPipe } from './pipe/create';
7+
import { runPipe } from './pipe/run';
8+
import { updatePipe } from './pipe/update';
9+
import { listPipes } from './pipe/list';
610
import cli from './utils/cli';
711
import debugMode from './utils/debug-mode';
812
import cliInit from './utils/init';
9-
13+
import { createMemory } from './memory/create';
14+
import { listMemories } from './memory/list';
15+
import { deleteMemory } from './memory/delete';
16+
import { uploadDocs } from './memory/upload-docs';
17+
import { embedDoc } from './memory/embed-doc';
18+
import { retriveFromMemory } from './memory/retrive';
19+
import { listDocs } from './memory/list-docs';
1020
const { flags, input, showHelp } = cli;
1121
const { clear, debug } = flags;
1222

@@ -50,4 +60,50 @@ const flag = (flg: string): boolean => Boolean(flags[flg]);
5060
if (command('docs-mcp-server')) {
5161
await docsMcpServer();
5262
}
63+
64+
if (command('pipe') && !flag('run') && !flag('update') && !flag('listPipes')) {
65+
await createPipe();
66+
}
67+
68+
if (command('pipe') && flag('run')) {
69+
await runPipe();
70+
}
71+
72+
if (command('pipe') && flag('update')) {
73+
await updatePipe();
74+
}
75+
76+
if (command('pipe') && flag('listPipes')) {
77+
await listPipes();
78+
}
79+
80+
81+
if (command('memory') && !flag('upload') && !flag('embed') && !flag('retrieve') && !flag('listDocs') && !flag('delete') && !flag('listMemories')) {
82+
await createMemory();
83+
}
84+
85+
if (command('memory') && flag('listMemories')) {
86+
await listMemories();
87+
}
88+
89+
if (command('memory') && flag('delete')) {
90+
await deleteMemory();
91+
}
92+
93+
if (command('memory') && flag('upload')) {
94+
await uploadDocs();
95+
}
96+
97+
if (command('memory') && flag('embed')) {
98+
await embedDoc();
99+
}
100+
101+
if (command('memory') && flag('retrieve')) {
102+
await retriveFromMemory();
103+
}
104+
105+
if (command('memory') && flag('listDocs')) {
106+
await listDocs();
107+
}
108+
53109
})();

packages/cli/src/memory/create.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { heading } from '@/utils/heading';
2+
import * as p from '@clack/prompts';
3+
import { Langbase, EmbeddingModels } from 'langbase';
4+
import { getApiKey } from '@/utils/get-langbase-api-key';
5+
import { memoryNameSchema } from 'types/memory';
6+
import { fromZodError } from 'zod-validation-error';
7+
8+
export async function createMemory() {
9+
const apiKey = await getApiKey();
10+
11+
p.intro(heading({ text: 'MEMORY', sub: 'Create a new memory' }));
12+
await p.group(
13+
{
14+
name: () =>
15+
p.text({
16+
message: 'Name of the memory',
17+
placeholder: 'cli-memory',
18+
validate: value => {
19+
const validatedName = memoryNameSchema.safeParse(value);
20+
if (!validatedName.success) {
21+
const validationError = fromZodError(
22+
validatedName.error
23+
).toString();
24+
return validationError;
25+
}
26+
return;
27+
}
28+
}),
29+
description: () =>
30+
p.text({
31+
message: 'Description of the memory',
32+
placeholder: 'This is a CLI memory'
33+
}),
34+
model: () =>
35+
p.select({
36+
message: 'Embedding Model',
37+
options: [
38+
{ value: 'openai:text-embedding-3-large', label: 'OpenAI Text Embedding 3 Large' },
39+
{ value: 'cohere:embed-multilingual-v3.0', label: 'Cohere Embed Multilingual v3.0' },
40+
{ value: 'cohere:embed-multilingual-light-v3.0', label: 'Cohere Embed Multilingual Light v3.0' },
41+
{ value: 'google:text-embedding-004', label: 'Google Text Embedding 004' }
42+
]
43+
}) as Promise<string>,
44+
topK: () =>
45+
p.text({
46+
message: 'Top K',
47+
placeholder: '10',
48+
validate: value => {
49+
if (Number(value) < 1 || Number(value) > 100) {
50+
return 'Top K must be between 1 and 100';
51+
}
52+
return;
53+
}
54+
}),
55+
chunkSize: () =>
56+
p.text({
57+
message: 'Chunk size',
58+
placeholder: '10000',
59+
validate: value => {
60+
if (Number(value) < 1024 || Number(value) > 300000) {
61+
return 'Chunk size must be between 1024 and 300000';
62+
}
63+
return;
64+
}
65+
}),
66+
chunkOverlap: () =>
67+
p.text({
68+
message: 'Chunk overlap',
69+
placeholder: '1000',
70+
validate: value => {
71+
if (Number(value) < 100 || Number(value) > 1000) {
72+
return 'Chunk overlap must be between 100 and 1000';
73+
}
74+
return;
75+
}
76+
}),
77+
78+
},
79+
{
80+
onCancel: () => {
81+
p.cancel('Operation cancelled.');
82+
process.exit(0);
83+
}
84+
}
85+
).then(async ({ name, description, model, topK, chunkSize, chunkOverlap }) => {
86+
const langbase = new Langbase({
87+
apiKey: apiKey
88+
});
89+
90+
const spinner = p.spinner();
91+
spinner.start('Memory is being created...');
92+
93+
const memory = await langbase.memories.create({
94+
name,
95+
description,
96+
top_k: Number(topK),
97+
chunk_size: Number(chunkSize),
98+
chunk_overlap: Number(chunkOverlap),
99+
embedding_model: model as EmbeddingModels,
100+
});
101+
102+
spinner.stop('Memory created successfully!');
103+
p.outro(heading({ text: 'MEMORY', sub: `${memory.name} created successfully` }));
104+
});
105+
}

packages/cli/src/memory/delete.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { heading } from '@/utils/heading';
2+
import * as p from '@clack/prompts';
3+
import { Langbase } from 'langbase';
4+
import { getApiKey } from '@/utils/get-langbase-api-key';
5+
import { fromZodError } from 'zod-validation-error';
6+
import { memoryNameSchema } from 'types/memory';
7+
8+
9+
export async function deleteMemory() {
10+
const apiKey = await getApiKey();
11+
12+
p.intro(heading({ text: 'MEMORY', sub: 'Delete a memory' }));
13+
await p.group(
14+
{
15+
name: () =>
16+
p.text({
17+
message: 'Name of the memory',
18+
placeholder: 'cli-memory',
19+
validate: value => {
20+
const validatedName = memoryNameSchema.safeParse(value);
21+
if (!validatedName.success) {
22+
const validationError = fromZodError(
23+
validatedName.error
24+
).toString();
25+
return validationError;
26+
}
27+
return;
28+
}
29+
})
30+
},
31+
{
32+
onCancel: () => {
33+
p.cancel('Operation cancelled.');
34+
process.exit(0);
35+
}
36+
}
37+
).then(async ({ name }) => {
38+
const langbase = new Langbase({
39+
apiKey: apiKey
40+
});
41+
42+
const spinner = p.spinner();
43+
spinner.start('Memory is being deleted...');
44+
45+
await langbase.memories.delete({name});
46+
47+
spinner.stop('Memory deleted successfully!');
48+
p.outro(heading({ text: 'MEMORY DELETED', sub: `${name} deleted successfully` }));
49+
});
50+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { heading } from '@/utils/heading';
2+
import * as p from '@clack/prompts';
3+
import { Langbase } from 'langbase';
4+
import { getApiKey } from '@/utils/get-langbase-api-key';
5+
import { fromZodError } from 'zod-validation-error';
6+
import { memoryNameSchema } from 'types/memory';
7+
8+
9+
export async function embedDoc() {
10+
const apiKey = await getApiKey();
11+
12+
p.intro(heading({ text: 'MEMORY', sub: 'Retry embedding a document' }));
13+
await p.group(
14+
{
15+
name: () =>
16+
p.text({
17+
message: 'Name of the memory',
18+
placeholder: 'cli-memory',
19+
validate: value => {
20+
const validatedName = memoryNameSchema.safeParse(value);
21+
if (!validatedName.success) {
22+
const validationError = fromZodError(
23+
validatedName.error
24+
).toString();
25+
return validationError;
26+
}
27+
return;
28+
}
29+
}),
30+
documentName: () =>
31+
p.text({
32+
message: 'Name of the document',
33+
placeholder: 'cli-document',
34+
}),
35+
},
36+
{
37+
onCancel: () => {
38+
p.cancel('Operation cancelled.');
39+
process.exit(0);
40+
}
41+
}
42+
).then(async ({ name, documentName }) => {
43+
const langbase = new Langbase({
44+
apiKey: apiKey
45+
});
46+
47+
const spinner = p.spinner();
48+
spinner.start('Document is being embedded...');
49+
50+
const response = await langbase.memories.documents.embeddings.retry({
51+
memoryName: name,
52+
documentName: documentName
53+
});
54+
55+
spinner.stop('Document embedded successfully!');
56+
console.log(response);
57+
});
58+
}

0 commit comments

Comments
 (0)