rosetta-cli 3.0.1__tar.gz → 3.0.4__tar.gz

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.
Files changed (33) hide show
  1. {rosetta_cli-3.0.1/rosetta_cli.egg-info → rosetta_cli-3.0.4}/PKG-INFO +35 -31
  2. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/README.md +34 -30
  3. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/env.template +4 -2
  4. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/pyproject.toml +1 -1
  5. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/cli.py +10 -8
  6. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/commands/cleanup_command.py +2 -2
  7. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/commands/parse_command.py +4 -2
  8. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/commands/publish_command.py +9 -2
  9. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/ragflow_client.py +7 -4
  10. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/rosetta_config.py +18 -5
  11. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/rosetta_publisher.py +12 -7
  12. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/services/document_service.py +3 -2
  13. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4/rosetta_cli.egg-info}/PKG-INFO +35 -31
  14. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/MANIFEST.in +0 -0
  15. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/__init__.py +0 -0
  16. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/__main__.py +0 -0
  17. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/commands/__init__.py +0 -0
  18. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/commands/base_command.py +0 -0
  19. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/commands/list_command.py +0 -0
  20. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/commands/verify_command.py +0 -0
  21. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/rosetta_auth.py +0 -0
  22. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/rosetta_utils.py +0 -0
  23. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/services/__init__.py +0 -0
  24. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/services/auth_service.py +0 -0
  25. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/services/dataset_service.py +0 -0
  26. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/services/document_data.py +0 -0
  27. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli/typing_utils.py +0 -0
  28. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli.egg-info/SOURCES.txt +0 -0
  29. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli.egg-info/dependency_links.txt +0 -0
  30. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli.egg-info/entry_points.txt +0 -0
  31. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli.egg-info/requires.txt +0 -0
  32. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/rosetta_cli.egg-info/top_level.txt +0 -0
  33. {rosetta_cli-3.0.1 → rosetta_cli-3.0.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rosetta-cli
3
- Version: 3.0.1
3
+ Version: 3.0.4
4
4
  Summary: Rosetta CLI for publishing knowledge base content to RAGFlow
5
5
  Author-email: Rosetta Team <rosetta-support@griddynamics.com>
6
6
  License-Expression: Apache-2.0
@@ -42,7 +42,7 @@ This directory contains the Python package for publishing knowledge base content
42
42
 
43
43
  - **🚀 Smart Publishing** - MD5 hash-based change detection (~77% faster republishing)
44
44
  - **🏗️ Modular Architecture** - Command pattern with service layer for maintainability
45
- - **🏷️ Tag-in-Title Format** - `[tag1][tag2] filename.ext` for powerful server-side filtering
45
+ - **🏷️ Metadata Tags** - path-derived tags in document metadata for `--tags` filtering
46
46
  - **📊 Parse Status Tracking** - Monitor document parsing progress with visual indicators
47
47
  - **🔄 Upsert Semantics** - No duplicates, republishing updates existing documents
48
48
  - **⏱️ Performance Timing** - All commands show execution time
@@ -143,9 +143,9 @@ File: /instructions/agents/r1/agents.md
143
143
 
144
144
  Published as:
145
145
  Document ID: b0ec4d56-6cc5-5bbd-9868-5d49afa2a7d8 (UUID from path)
146
- Title: [instructions][agents][r1] agents.md
146
+ Title: agents.md (path relative to the release folder, no tag prefixes)
147
147
  Dataset: aia-r1 (from template: aia-{release})
148
- Tags: ["instructions", "agents", "r1"] (in metadata)
148
+ Tags: ["instructions", "agents", "r1", "agents.md"] (in metadata only)
149
149
  Domain: instructions (first folder)
150
150
  Release: r1 (auto-detected from path)
151
151
  Content Hash: abc123... (MD5 of content)
@@ -180,7 +180,7 @@ uvx rosetta-cli@latest list-dataset --dataset aia-r1
180
180
  ```
181
181
 
182
182
  **Output shows:**
183
- - Document title (with tag prefixes)
183
+ - Document title (path relative to the release folder, no tag prefixes)
184
184
  - Document ID, file size, parse status, chunk count
185
185
  - Metadata (tags, domain, release, source path)
186
186
 
@@ -212,7 +212,7 @@ uvx rosetta-cli@latest cleanup-dataset --dataset aia-r1 --tags "r1,agents" --for
212
212
  ⚠️ **Warning:** Without `--prefix` or `--tags`, this deletes ALL documents. Use `--dry-run` first.
213
213
 
214
214
  **Filtering Options:**
215
- - `--prefix`: Match documents by title prefix (e.g., `"[instructions]"`)
215
+ - `--prefix`: Match documents by literal title prefix (e.g., `"aqa-phase"`, `"core/skills"`)
216
216
  - `--tags`: Match documents by metadata tags (e.g., `"r1 agents"` or `"r1,agents"`)
217
217
  - Uses OR logic: finds documents with ANY of the specified tags
218
218
  - Server-side filtering for efficiency
@@ -360,7 +360,7 @@ results = publisher.publish(
360
360
  force=False, # Skip unchanged files
361
361
  dry_run=False, # Preview mode
362
362
  no_parse=False, # Skip parsing after upload
363
- parse_timeout=300 # Parse timeout in seconds
363
+ parse_timeout=1200 # Parse timeout in seconds
364
364
  )
365
365
 
366
366
  print(f"Published: {results.published_count}")
@@ -374,7 +374,7 @@ print(f"Failed: {results.failed_count}")
374
374
  File: /instructions/agents/r1/bootstrap.md
375
375
 
376
376
  Extracted:
377
- Tags: ["instructions", "agents", "r1"]
377
+ Tags: ["instructions", "agents", "r1", "bootstrap.md"]
378
378
  Domain: instructions
379
379
  Release: r1
380
380
  Title: bootstrap.md
@@ -382,47 +382,50 @@ Extracted:
382
382
  Document ID: uuid-from-path
383
383
  ```
384
384
 
385
- ## 🎯 Tag-in-Title Format
385
+ ## 🎯 Titles and Tags
386
386
 
387
- ### What is Tag-in-Title?
387
+ ### Document Titles
388
388
 
389
- Documents are stored with tags as prefixes for server-side filtering:
389
+ Titles carry no tag prefixes. A title is the document path relative to its
390
+ release folder, or just the filename for files outside an `instructions/<release>` tree:
390
391
 
391
392
  ```
392
- Format: [tag1][tag2][tag3] filename.ext
393
-
394
- Examples:
395
- [instructions][agents][r1] agents.md
396
- [business][project] RFP.pdf
393
+ File: /instructions/agents/r1/agents.md → Title: agents.md
394
+ File: /instructions/r3/core/skills/coding/SKILL.md → Title: core/skills/coding/SKILL.md
395
+ File: /business/project/RFP.pdf → Title: RFP.pdf
397
396
  ```
398
397
 
399
- ### Why Two Locations?
400
-
401
- Tags are stored in **both title and metadata**:
398
+ ### Where Tags Live
402
399
 
403
- **Title:** Fast server-side keyword search
404
- **Metadata:** Precise client-side filtering with complex queries
400
+ Tags are stored in document **metadata** (`meta_fields.tags`) only, never in the title.
405
401
 
406
402
  ### How Tags are Generated
407
403
 
408
- Tags come from **folder structure only**:
404
+ Tags come from the file path, plus optional Markdown frontmatter `tags`:
409
405
 
410
406
  ```
411
- File: /instructions/agents/r1/bootstrap.md
412
- Folders: instructions / agents / r1 / (file)
413
- Tags: [instructions][agents][r1]
407
+ File: /instructions/r3/core/skills/coding/SKILL.md
408
+ Tags: instructions, r3, core, skills, coding, SKILL.md,
409
+ coding/SKILL.md, skills/coding/SKILL.md
414
410
  ```
415
411
 
412
+ - Every folder in the path
413
+ - The filename, with extension
414
+ - The last two and last three path segments, joined with `/`
415
+ - Any `tags:` values from Markdown frontmatter (`.md`/`.markdown` only)
416
+
416
417
  ### Using Tags for Filtering
417
418
 
418
419
  ```bash
419
420
  # Delete all instruction documents
420
- uvx rosetta-cli@latest cleanup-dataset --prefix "[instructions]"
421
+ uvx rosetta-cli@latest cleanup-dataset --tags "instructions"
421
422
 
422
- # Delete all r1 agent documents
423
- uvx rosetta-cli@latest cleanup-dataset --prefix "[instructions][agents][r1]"
423
+ # Delete documents tagged "agents" OR "r1"
424
+ uvx rosetta-cli@latest cleanup-dataset --tags "agents,r1"
424
425
  ```
425
426
 
427
+ Use `--prefix` for literal title-prefix matching instead, e.g. `--prefix "core/skills"`.
428
+
426
429
  ## 💻 Usage Examples
427
430
 
428
431
  ### Example 1: First-Time Setup
@@ -549,10 +552,11 @@ nano .env
549
552
 
550
553
  ### Documents Not Showing Tags
551
554
 
552
- Tags should appear in title with format `[tag1][tag2]`:
555
+ Tags live in metadata, not in the title. `list-dataset` prints them on their own line:
553
556
  ```bash
554
557
  uvx rosetta-cli@latest list-dataset
555
- # Output: 1. [instructions][agents][r1] agents.md
558
+ # Output: 1. agents.md
559
+ # Tags: instructions, agents, r1, agents.md
556
560
  ```
557
561
 
558
562
  ## 🚦 Performance Tips
@@ -591,7 +595,7 @@ RAGFLOW_CHUNK_TOKEN_NUM=1024
591
595
 
592
596
  ```bash
593
597
  # Fast: Delete specific documents
594
- uvx rosetta-cli@latest cleanup-dataset --prefix "[instructions][agents]" --force
598
+ uvx rosetta-cli@latest cleanup-dataset --tags "agents" --force
595
599
 
596
600
  # Slow: Delete and republish everything
597
601
  uvx rosetta-cli@latest cleanup-dataset --force
@@ -15,7 +15,7 @@ This directory contains the Python package for publishing knowledge base content
15
15
 
16
16
  - **🚀 Smart Publishing** - MD5 hash-based change detection (~77% faster republishing)
17
17
  - **🏗️ Modular Architecture** - Command pattern with service layer for maintainability
18
- - **🏷️ Tag-in-Title Format** - `[tag1][tag2] filename.ext` for powerful server-side filtering
18
+ - **🏷️ Metadata Tags** - path-derived tags in document metadata for `--tags` filtering
19
19
  - **📊 Parse Status Tracking** - Monitor document parsing progress with visual indicators
20
20
  - **🔄 Upsert Semantics** - No duplicates, republishing updates existing documents
21
21
  - **⏱️ Performance Timing** - All commands show execution time
@@ -116,9 +116,9 @@ File: /instructions/agents/r1/agents.md
116
116
 
117
117
  Published as:
118
118
  Document ID: b0ec4d56-6cc5-5bbd-9868-5d49afa2a7d8 (UUID from path)
119
- Title: [instructions][agents][r1] agents.md
119
+ Title: agents.md (path relative to the release folder, no tag prefixes)
120
120
  Dataset: aia-r1 (from template: aia-{release})
121
- Tags: ["instructions", "agents", "r1"] (in metadata)
121
+ Tags: ["instructions", "agents", "r1", "agents.md"] (in metadata only)
122
122
  Domain: instructions (first folder)
123
123
  Release: r1 (auto-detected from path)
124
124
  Content Hash: abc123... (MD5 of content)
@@ -153,7 +153,7 @@ uvx rosetta-cli@latest list-dataset --dataset aia-r1
153
153
  ```
154
154
 
155
155
  **Output shows:**
156
- - Document title (with tag prefixes)
156
+ - Document title (path relative to the release folder, no tag prefixes)
157
157
  - Document ID, file size, parse status, chunk count
158
158
  - Metadata (tags, domain, release, source path)
159
159
 
@@ -185,7 +185,7 @@ uvx rosetta-cli@latest cleanup-dataset --dataset aia-r1 --tags "r1,agents" --for
185
185
  ⚠️ **Warning:** Without `--prefix` or `--tags`, this deletes ALL documents. Use `--dry-run` first.
186
186
 
187
187
  **Filtering Options:**
188
- - `--prefix`: Match documents by title prefix (e.g., `"[instructions]"`)
188
+ - `--prefix`: Match documents by literal title prefix (e.g., `"aqa-phase"`, `"core/skills"`)
189
189
  - `--tags`: Match documents by metadata tags (e.g., `"r1 agents"` or `"r1,agents"`)
190
190
  - Uses OR logic: finds documents with ANY of the specified tags
191
191
  - Server-side filtering for efficiency
@@ -333,7 +333,7 @@ results = publisher.publish(
333
333
  force=False, # Skip unchanged files
334
334
  dry_run=False, # Preview mode
335
335
  no_parse=False, # Skip parsing after upload
336
- parse_timeout=300 # Parse timeout in seconds
336
+ parse_timeout=1200 # Parse timeout in seconds
337
337
  )
338
338
 
339
339
  print(f"Published: {results.published_count}")
@@ -347,7 +347,7 @@ print(f"Failed: {results.failed_count}")
347
347
  File: /instructions/agents/r1/bootstrap.md
348
348
 
349
349
  Extracted:
350
- Tags: ["instructions", "agents", "r1"]
350
+ Tags: ["instructions", "agents", "r1", "bootstrap.md"]
351
351
  Domain: instructions
352
352
  Release: r1
353
353
  Title: bootstrap.md
@@ -355,47 +355,50 @@ Extracted:
355
355
  Document ID: uuid-from-path
356
356
  ```
357
357
 
358
- ## 🎯 Tag-in-Title Format
358
+ ## 🎯 Titles and Tags
359
359
 
360
- ### What is Tag-in-Title?
360
+ ### Document Titles
361
361
 
362
- Documents are stored with tags as prefixes for server-side filtering:
362
+ Titles carry no tag prefixes. A title is the document path relative to its
363
+ release folder, or just the filename for files outside an `instructions/<release>` tree:
363
364
 
364
365
  ```
365
- Format: [tag1][tag2][tag3] filename.ext
366
-
367
- Examples:
368
- [instructions][agents][r1] agents.md
369
- [business][project] RFP.pdf
366
+ File: /instructions/agents/r1/agents.md → Title: agents.md
367
+ File: /instructions/r3/core/skills/coding/SKILL.md → Title: core/skills/coding/SKILL.md
368
+ File: /business/project/RFP.pdf → Title: RFP.pdf
370
369
  ```
371
370
 
372
- ### Why Two Locations?
373
-
374
- Tags are stored in **both title and metadata**:
371
+ ### Where Tags Live
375
372
 
376
- **Title:** Fast server-side keyword search
377
- **Metadata:** Precise client-side filtering with complex queries
373
+ Tags are stored in document **metadata** (`meta_fields.tags`) only, never in the title.
378
374
 
379
375
  ### How Tags are Generated
380
376
 
381
- Tags come from **folder structure only**:
377
+ Tags come from the file path, plus optional Markdown frontmatter `tags`:
382
378
 
383
379
  ```
384
- File: /instructions/agents/r1/bootstrap.md
385
- Folders: instructions / agents / r1 / (file)
386
- Tags: [instructions][agents][r1]
380
+ File: /instructions/r3/core/skills/coding/SKILL.md
381
+ Tags: instructions, r3, core, skills, coding, SKILL.md,
382
+ coding/SKILL.md, skills/coding/SKILL.md
387
383
  ```
388
384
 
385
+ - Every folder in the path
386
+ - The filename, with extension
387
+ - The last two and last three path segments, joined with `/`
388
+ - Any `tags:` values from Markdown frontmatter (`.md`/`.markdown` only)
389
+
389
390
  ### Using Tags for Filtering
390
391
 
391
392
  ```bash
392
393
  # Delete all instruction documents
393
- uvx rosetta-cli@latest cleanup-dataset --prefix "[instructions]"
394
+ uvx rosetta-cli@latest cleanup-dataset --tags "instructions"
394
395
 
395
- # Delete all r1 agent documents
396
- uvx rosetta-cli@latest cleanup-dataset --prefix "[instructions][agents][r1]"
396
+ # Delete documents tagged "agents" OR "r1"
397
+ uvx rosetta-cli@latest cleanup-dataset --tags "agents,r1"
397
398
  ```
398
399
 
400
+ Use `--prefix` for literal title-prefix matching instead, e.g. `--prefix "core/skills"`.
401
+
399
402
  ## 💻 Usage Examples
400
403
 
401
404
  ### Example 1: First-Time Setup
@@ -522,10 +525,11 @@ nano .env
522
525
 
523
526
  ### Documents Not Showing Tags
524
527
 
525
- Tags should appear in title with format `[tag1][tag2]`:
528
+ Tags live in metadata, not in the title. `list-dataset` prints them on their own line:
526
529
  ```bash
527
530
  uvx rosetta-cli@latest list-dataset
528
- # Output: 1. [instructions][agents][r1] agents.md
531
+ # Output: 1. agents.md
532
+ # Tags: instructions, agents, r1, agents.md
529
533
  ```
530
534
 
531
535
  ## 🚦 Performance Tips
@@ -564,7 +568,7 @@ RAGFLOW_CHUNK_TOKEN_NUM=1024
564
568
 
565
569
  ```bash
566
570
  # Fast: Delete specific documents
567
- uvx rosetta-cli@latest cleanup-dataset --prefix "[instructions][agents]" --force
571
+ uvx rosetta-cli@latest cleanup-dataset --tags "agents" --force
568
572
 
569
573
  # Slow: Delete and republish everything
570
574
  uvx rosetta-cli@latest cleanup-dataset --force
@@ -42,6 +42,8 @@ RAGFLOW_AUTO_KEYWORDS=0
42
42
  RAGFLOW_AUTO_QUESTIONS=0
43
43
  # Page size for listing operations (default: 1000)
44
44
  RAGFLOW_PAGE_SIZE=1000
45
- # Timeout for document parsing operations in seconds (default: 300 = 5 minutes)
46
- RAGFLOW_PARSE_TIMEOUT=300
45
+ # Timeout for document parsing operations in seconds (default: 1200 = 20 minutes)
46
+ RAGFLOW_PARSE_TIMEOUT=1200
47
+ # HTTP request timeout for RAGFlow health checks in seconds (default: 30)
48
+ RAGFLOW_TIMEOUT=30
47
49
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rosetta-cli"
7
- version = "3.0.1"
7
+ version = "3.0.4"
8
8
  description = "Rosetta CLI for publishing knowledge base content to RAGFlow"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -134,9 +134,10 @@ Performance Notes:
134
134
  - Change detection skips unchanged files (77% faster)
135
135
  - API key verification timing shown when applicable
136
136
 
137
- Tag-in-Title Format:
138
- - Documents are published with tags in title: [tag1][tag2] filename.ext
139
- - Example: [instructions][agents][r1] agents.md
137
+ Titles and Tags:
138
+ - Titles carry no tag prefixes: path relative to the release folder, or the filename
139
+ - Example: core/skills/coding/SKILL.md
140
+ - Tags are stored in metadata only; filter with --tags (--prefix matches literal titles)
140
141
 
141
142
  Frontmatter Metadata (publish flow):
142
143
  - Supported keys: tags, sort_order
@@ -192,8 +193,8 @@ Frontmatter Metadata (publish flow):
192
193
  publish_parser.add_argument(
193
194
  '--parse-timeout',
194
195
  type=int,
195
- default=300,
196
- help='Timeout for parsing in seconds (default: 300)'
196
+ default=None,
197
+ help='Timeout for parsing in seconds (default: RAGFLOW_PARSE_TIMEOUT, or 1200)'
197
198
  )
198
199
  publish_parser.add_argument(
199
200
  '--env',
@@ -331,8 +332,8 @@ Frontmatter Metadata (publish flow):
331
332
  parse_parser.add_argument(
332
333
  '--parse-timeout',
333
334
  type=int,
334
- default=300,
335
- help='Timeout for parsing in seconds (default: 300)'
335
+ default=None,
336
+ help='Timeout for parsing in seconds (default: RAGFLOW_PARSE_TIMEOUT, or 1200)'
336
337
  )
337
338
  parse_parser.add_argument(
338
339
  '--env',
@@ -376,7 +377,8 @@ Frontmatter Metadata (publish flow):
376
377
  embedding_model=config.embedding_model,
377
378
  chunk_method=config.chunk_method,
378
379
  parser_config=config.parser_config,
379
- page_size=config.page_size
380
+ page_size=config.page_size,
381
+ timeout=config.timeout
380
382
  )
381
383
 
382
384
  return execute_command(args.command, args, client, config)
@@ -94,13 +94,13 @@ class CleanupCommand(BaseCommand):
94
94
  # Filter by tags (metadata condition)
95
95
  tags_list = self._parse_tags(args.tags)
96
96
  filtered_documents = document_service.filter_documents_by_tags(
97
- dataset, tags_list
97
+ dataset, tags_list, limit=self.config.page_size
98
98
  )
99
99
  print(f"\nFiltered {len(filtered_documents)} document(s) with tags: {', '.join(tags_list)}\n")
100
100
  elif args.prefix:
101
101
  # Filter by prefix
102
102
  filtered_documents = document_service.filter_documents_by_prefix(
103
- dataset, args.prefix
103
+ dataset, args.prefix, limit=self.config.page_size
104
104
  )
105
105
  print(f"\nFiltered {len(filtered_documents)} document(s) matching prefix '{args.prefix}'\n")
106
106
  else:
@@ -25,8 +25,10 @@ class ParseCommand(BaseCommand):
25
25
  """Execute parse command."""
26
26
  self._start_timing()
27
27
 
28
- # CLI flag must override config default for this run.
29
- self.config.parse_timeout = args.parse_timeout
28
+ # Explicit CLI flag wins for this run; an unset flag keeps the
29
+ # configured (RAGFLOW_PARSE_TIMEOUT) value.
30
+ if getattr(args, "parse_timeout", None) is not None:
31
+ self.config.parse_timeout = args.parse_timeout
30
32
 
31
33
  # Verify authentication before any dataset auto-detection touches the API.
32
34
  AuthService.verify_or_exit(self.client, self.config)
@@ -25,13 +25,19 @@ class PublishCommand(BaseCommand):
25
25
  Execute publish command.
26
26
 
27
27
  Args:
28
- args: Command arguments with path, dry_run, force, no_parse flags
28
+ args: Command arguments with path, dry_run, force, no_parse,
29
+ parse_timeout flags
29
30
 
30
31
  Returns:
31
32
  0 if successful, 1 if failed
32
33
  """
33
34
  self._start_timing()
34
35
 
36
+ # Explicit CLI flag wins for this run; an unset flag keeps the
37
+ # configured (RAGFLOW_PARSE_TIMEOUT) value.
38
+ if getattr(args, "parse_timeout", None) is not None:
39
+ self.config.parse_timeout = args.parse_timeout
40
+
35
41
  # Print header
36
42
  print(f"Publishing knowledge base content from: {args.path}")
37
43
  self._print_header_with_api_key()
@@ -47,7 +53,8 @@ class PublishCommand(BaseCommand):
47
53
  self.client,
48
54
  str(workspace_root),
49
55
  dataset_default=self.config.dataset_default,
50
- dataset_template=self.config.dataset_template
56
+ dataset_template=self.config.dataset_template,
57
+ parse_timeout=self.config.parse_timeout
51
58
  )
52
59
 
53
60
  # Publish
@@ -6,8 +6,8 @@ This module provides a wrapper around the ragflow-sdk for Rosetta-specific opera
6
6
  Key Features:
7
7
  - Dataset management with template resolution (aia-{release})
8
8
  - Document upload with change detection (MD5 hashing)
9
- - Tag-in-title format: [tag1][tag2][tag3] filename.ext
10
- - Two-stage filtering support (server keyword + client metadata)
9
+ - Plain titles (path relative to the release folder, or the filename)
10
+ - Tags stored in meta_fields for metadata filtering
11
11
  """
12
12
 
13
13
  import hashlib
@@ -90,7 +90,7 @@ class RAGFlowClient:
90
90
  Wrapper class for RAGFlow SDK operations.
91
91
 
92
92
  Provides high-level methods for dataset and document management
93
- with Rosetta-specific functionality like tag-in-title format and
93
+ with Rosetta-specific functionality like metadata tagging and
94
94
  change detection.
95
95
 
96
96
  Usage:
@@ -406,7 +406,10 @@ class RAGFlowClient:
406
406
  if cached is not None:
407
407
  return cached
408
408
 
409
- # Filter by name (RAGFlow does substring, we verify exact match)
409
+ # Filter by name (RAGFlow does substring, we verify exact match).
410
+ # page_size=10 is intentional and sufficient: dataset names are
411
+ # unique, so this lookup can return at most one exact match.
412
+ # Do not "fix" this to a larger page size or a pagination loop.
410
413
  with _timed(f"list_datasets(name={name})"):
411
414
  datasets = self._client.list_datasets(name=name, page_size=10)
412
415
  # Filter for exact match
@@ -19,6 +19,11 @@ logger = logging.getLogger(__name__)
19
19
 
20
20
  ENV_FILE_ENV_VAR = "ROSETTA_CLI_ENV_FILE"
21
21
 
22
+ # Default timeouts in seconds. Single source of truth for the dataclass
23
+ # defaults, the env-var fallbacks, and env.template.
24
+ DEFAULT_TIMEOUT = 30
25
+ DEFAULT_PARSE_TIMEOUT = 1200
26
+
22
27
 
23
28
  def _candidate_env_names(env_name: str | None) -> list[str]:
24
29
  names: list[str] = []
@@ -92,6 +97,7 @@ class RosettaConfig:
92
97
  RAGFLOW_AUTO_QUESTIONS: Auto-generate questions per chunk (default: 0)
93
98
  RAGFLOW_PAGE_SIZE: Page size for listing operations (default: 1000)
94
99
  RAGFLOW_PARSE_TIMEOUT: Timeout for parsing operations in seconds (default: 1200)
100
+ RAGFLOW_TIMEOUT: HTTP request timeout in seconds (default: 30)
95
101
  ENVIRONMENT: Environment name (default: "local")
96
102
 
97
103
  Examples:
@@ -112,7 +118,8 @@ class RosettaConfig:
112
118
  parser_config: JsonDict | None = None
113
119
  environment: str = "local"
114
120
  page_size: int = 1000
115
- parse_timeout: int = 300
121
+ parse_timeout: int = DEFAULT_PARSE_TIMEOUT
122
+ timeout: int = DEFAULT_TIMEOUT
116
123
 
117
124
  @classmethod
118
125
  def from_env(
@@ -216,7 +223,8 @@ class RosettaConfig:
216
223
 
217
224
  # Pagination and timeout settings
218
225
  page_size = int(os.getenv("RAGFLOW_PAGE_SIZE", "1000"))
219
- parse_timeout = int(os.getenv("RAGFLOW_PARSE_TIMEOUT", "1200"))
226
+ parse_timeout = int(os.getenv("RAGFLOW_PARSE_TIMEOUT", str(DEFAULT_PARSE_TIMEOUT)))
227
+ timeout = int(os.getenv("RAGFLOW_TIMEOUT", str(DEFAULT_TIMEOUT)))
220
228
 
221
229
  # Parser configuration for naive chunking
222
230
  parser_config: JsonDict | None = None
@@ -243,7 +251,8 @@ class RosettaConfig:
243
251
  parser_config=parser_config,
244
252
  environment=environment,
245
253
  page_size=page_size,
246
- parse_timeout=parse_timeout
254
+ parse_timeout=parse_timeout,
255
+ timeout=timeout
247
256
  )
248
257
 
249
258
  def validate(self) -> bool:
@@ -268,7 +277,9 @@ class RosettaConfig:
268
277
  )
269
278
 
270
279
  if not self.api_key.startswith("ragflow-"):
271
- logger.warning("API key should start with 'ragflow-', got: %s...", self.api_key[:10])
280
+ # Never log any part of the key: the "ragflow-" prefix is 8 chars, so a
281
+ # 10-char excerpt leaks secret material, and the caller knows their own key.
282
+ logger.warning("API key should start with 'ragflow-'")
272
283
 
273
284
  return True
274
285
 
@@ -321,7 +332,9 @@ class RosettaConfig:
321
332
 
322
333
  def __str__(self) -> str:
323
334
  """String representation (masks API key)"""
324
- masked_key = f"{self.api_key[:10]}..." if len(self.api_key) > 10 else "***"
335
+ # Show only the 8-char "ragflow-" prefix. A 10-char excerpt would expose two
336
+ # characters of secret material, which the docstring's "masks API key" rules out.
337
+ masked_key = f"{self.api_key[:8]}..." if len(self.api_key) > 8 else "***"
325
338
  return (
326
339
  f"RosettaConfig(\n"
327
340
  f" base_url={self.base_url}\n"
@@ -6,9 +6,8 @@ from folder structure.
6
6
 
7
7
  Features:
8
8
  - RAGFlow SDK integration for document upload and management
9
- - Tag-in-title format: [tag1][tag2] filename.ext
10
- - Preserves dots in filenames (e.g., "agents.md" stays "agents.md")
11
- - Two-location tag storage: title + meta_fields for optimal search performance
9
+ - Plain filename titles (e.g., "agents.md" stays "agents.md")
10
+ - Tags stored in meta_fields for metadata filtering
12
11
  - Dataset-based organization
13
12
  - MD5 hash-based change detection
14
13
  """
@@ -26,6 +25,7 @@ from typing import cast
26
25
  from .services.document_service import DocumentService
27
26
  from .services.document_data import DocumentData
28
27
  from .ragflow_client import DocumentMetadata, RAGFlowClient, RAGFlowClientError
28
+ from .rosetta_config import DEFAULT_PARSE_TIMEOUT
29
29
  from .typing_utils import DocumentLike, JsonDict
30
30
 
31
31
  # Extensions RAGFlow can actually parse (from ragflow source: api/utils/file_utils.py).
@@ -80,7 +80,8 @@ class ContentPublisher:
80
80
  dataset_default: str = "aia",
81
81
  dataset_template: str = "aia-{release}",
82
82
  enable_change_tracking: bool = True,
83
- file_extensions: list[str] | None = None
83
+ file_extensions: list[str] | None = None,
84
+ parse_timeout: int = DEFAULT_PARSE_TIMEOUT
84
85
  ):
85
86
  """
86
87
  Initialize the publisher.
@@ -92,6 +93,7 @@ class ContentPublisher:
92
93
  dataset_template: Dataset name template (can use {release} placeholder)
93
94
  enable_change_tracking: Enable hash-based change detection (default: True)
94
95
  file_extensions: List of file extensions to publish (default: None = all files)
96
+ parse_timeout: Max seconds to wait for parsing (default: 1200)
95
97
  """
96
98
  self.client = client
97
99
  self.workspace_root = Path(workspace_root).resolve()
@@ -99,6 +101,7 @@ class ContentPublisher:
99
101
  self.dataset_template = dataset_template
100
102
  self.enable_change_tracking = enable_change_tracking
101
103
  self.file_extensions = file_extensions # None = all files (no extension filter)
104
+ self.parse_timeout = parse_timeout
102
105
  self._skip_names = {'.DS_Store', 'Thumbs.db', '.gitkeep', '.mcp.json'}
103
106
  self._skip_folders = {'.cursor-plugin', '.claude-plugin'}
104
107
 
@@ -502,12 +505,12 @@ class ContentPublisher:
502
505
  if docs_to_wait:
503
506
  # Use DocumentService for consistent waiting with progress bar
504
507
  doc_service = DocumentService(self.client)
505
- doc_service.wait_for_parsing(docs_to_wait)
508
+ doc_service.wait_for_parsing(docs_to_wait, self.parse_timeout)
506
509
 
507
510
  def _wait_for_all_parsing_with_progress(
508
511
  self,
509
512
  documents: list[JsonDict],
510
- timeout: int = 300, # 5 minutes
513
+ timeout: int | None = None,
511
514
  poll_interval: float = 0.5
512
515
  ) -> None:
513
516
  """
@@ -517,10 +520,12 @@ class ContentPublisher:
517
520
 
518
521
  Args:
519
522
  documents: List of {"id": doc_id, "name": name, "dataset_id": dataset_id, "folder": folder}
520
- timeout: Max seconds to wait
523
+ timeout: Max seconds to wait (default: None = configured parse_timeout)
521
524
  poll_interval: Seconds between status checks (reduced to 0.5 for smoother progress)
522
525
  """
523
526
  doc_service = DocumentService(self.client)
527
+ if timeout is None:
528
+ timeout = self.parse_timeout
524
529
  doc_service.wait_for_parsing(documents, timeout, poll_interval)
525
530
 
526
531
  def _has_content_changed_cached(self, cache: DocumentData) -> bool:
@@ -10,6 +10,7 @@ from typing import cast
10
10
 
11
11
  from tqdm import tqdm
12
12
  from ..ragflow_client import RAGFlowClient
13
+ from ..rosetta_config import DEFAULT_PARSE_TIMEOUT
13
14
  from ..typing_utils import DatasetLike, DocumentLike, JsonDict
14
15
 
15
16
 
@@ -227,7 +228,7 @@ class DocumentService:
227
228
  def wait_for_parsing(
228
229
  self,
229
230
  documents: list[JsonDict],
230
- timeout: int = 300,
231
+ timeout: int = DEFAULT_PARSE_TIMEOUT,
231
232
  poll_interval: float = 0.5
232
233
  ) -> tuple[int, int]:
233
234
  """
@@ -235,7 +236,7 @@ class DocumentService:
235
236
 
236
237
  Args:
237
238
  documents: List of {"id": doc_id, "name": name, "dataset_id": dataset_id, "folder": folder}
238
- timeout: Max seconds to wait (default: 300 = 5 minutes)
239
+ timeout: Max seconds to wait (default: DEFAULT_PARSE_TIMEOUT = 1200 = 20 minutes)
239
240
  poll_interval: Seconds between status checks (default: 0.5 for smooth progress)
240
241
 
241
242
  Returns:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rosetta-cli
3
- Version: 3.0.1
3
+ Version: 3.0.4
4
4
  Summary: Rosetta CLI for publishing knowledge base content to RAGFlow
5
5
  Author-email: Rosetta Team <rosetta-support@griddynamics.com>
6
6
  License-Expression: Apache-2.0
@@ -42,7 +42,7 @@ This directory contains the Python package for publishing knowledge base content
42
42
 
43
43
  - **🚀 Smart Publishing** - MD5 hash-based change detection (~77% faster republishing)
44
44
  - **🏗️ Modular Architecture** - Command pattern with service layer for maintainability
45
- - **🏷️ Tag-in-Title Format** - `[tag1][tag2] filename.ext` for powerful server-side filtering
45
+ - **🏷️ Metadata Tags** - path-derived tags in document metadata for `--tags` filtering
46
46
  - **📊 Parse Status Tracking** - Monitor document parsing progress with visual indicators
47
47
  - **🔄 Upsert Semantics** - No duplicates, republishing updates existing documents
48
48
  - **⏱️ Performance Timing** - All commands show execution time
@@ -143,9 +143,9 @@ File: /instructions/agents/r1/agents.md
143
143
 
144
144
  Published as:
145
145
  Document ID: b0ec4d56-6cc5-5bbd-9868-5d49afa2a7d8 (UUID from path)
146
- Title: [instructions][agents][r1] agents.md
146
+ Title: agents.md (path relative to the release folder, no tag prefixes)
147
147
  Dataset: aia-r1 (from template: aia-{release})
148
- Tags: ["instructions", "agents", "r1"] (in metadata)
148
+ Tags: ["instructions", "agents", "r1", "agents.md"] (in metadata only)
149
149
  Domain: instructions (first folder)
150
150
  Release: r1 (auto-detected from path)
151
151
  Content Hash: abc123... (MD5 of content)
@@ -180,7 +180,7 @@ uvx rosetta-cli@latest list-dataset --dataset aia-r1
180
180
  ```
181
181
 
182
182
  **Output shows:**
183
- - Document title (with tag prefixes)
183
+ - Document title (path relative to the release folder, no tag prefixes)
184
184
  - Document ID, file size, parse status, chunk count
185
185
  - Metadata (tags, domain, release, source path)
186
186
 
@@ -212,7 +212,7 @@ uvx rosetta-cli@latest cleanup-dataset --dataset aia-r1 --tags "r1,agents" --for
212
212
  ⚠️ **Warning:** Without `--prefix` or `--tags`, this deletes ALL documents. Use `--dry-run` first.
213
213
 
214
214
  **Filtering Options:**
215
- - `--prefix`: Match documents by title prefix (e.g., `"[instructions]"`)
215
+ - `--prefix`: Match documents by literal title prefix (e.g., `"aqa-phase"`, `"core/skills"`)
216
216
  - `--tags`: Match documents by metadata tags (e.g., `"r1 agents"` or `"r1,agents"`)
217
217
  - Uses OR logic: finds documents with ANY of the specified tags
218
218
  - Server-side filtering for efficiency
@@ -360,7 +360,7 @@ results = publisher.publish(
360
360
  force=False, # Skip unchanged files
361
361
  dry_run=False, # Preview mode
362
362
  no_parse=False, # Skip parsing after upload
363
- parse_timeout=300 # Parse timeout in seconds
363
+ parse_timeout=1200 # Parse timeout in seconds
364
364
  )
365
365
 
366
366
  print(f"Published: {results.published_count}")
@@ -374,7 +374,7 @@ print(f"Failed: {results.failed_count}")
374
374
  File: /instructions/agents/r1/bootstrap.md
375
375
 
376
376
  Extracted:
377
- Tags: ["instructions", "agents", "r1"]
377
+ Tags: ["instructions", "agents", "r1", "bootstrap.md"]
378
378
  Domain: instructions
379
379
  Release: r1
380
380
  Title: bootstrap.md
@@ -382,47 +382,50 @@ Extracted:
382
382
  Document ID: uuid-from-path
383
383
  ```
384
384
 
385
- ## 🎯 Tag-in-Title Format
385
+ ## 🎯 Titles and Tags
386
386
 
387
- ### What is Tag-in-Title?
387
+ ### Document Titles
388
388
 
389
- Documents are stored with tags as prefixes for server-side filtering:
389
+ Titles carry no tag prefixes. A title is the document path relative to its
390
+ release folder, or just the filename for files outside an `instructions/<release>` tree:
390
391
 
391
392
  ```
392
- Format: [tag1][tag2][tag3] filename.ext
393
-
394
- Examples:
395
- [instructions][agents][r1] agents.md
396
- [business][project] RFP.pdf
393
+ File: /instructions/agents/r1/agents.md → Title: agents.md
394
+ File: /instructions/r3/core/skills/coding/SKILL.md → Title: core/skills/coding/SKILL.md
395
+ File: /business/project/RFP.pdf → Title: RFP.pdf
397
396
  ```
398
397
 
399
- ### Why Two Locations?
400
-
401
- Tags are stored in **both title and metadata**:
398
+ ### Where Tags Live
402
399
 
403
- **Title:** Fast server-side keyword search
404
- **Metadata:** Precise client-side filtering with complex queries
400
+ Tags are stored in document **metadata** (`meta_fields.tags`) only, never in the title.
405
401
 
406
402
  ### How Tags are Generated
407
403
 
408
- Tags come from **folder structure only**:
404
+ Tags come from the file path, plus optional Markdown frontmatter `tags`:
409
405
 
410
406
  ```
411
- File: /instructions/agents/r1/bootstrap.md
412
- Folders: instructions / agents / r1 / (file)
413
- Tags: [instructions][agents][r1]
407
+ File: /instructions/r3/core/skills/coding/SKILL.md
408
+ Tags: instructions, r3, core, skills, coding, SKILL.md,
409
+ coding/SKILL.md, skills/coding/SKILL.md
414
410
  ```
415
411
 
412
+ - Every folder in the path
413
+ - The filename, with extension
414
+ - The last two and last three path segments, joined with `/`
415
+ - Any `tags:` values from Markdown frontmatter (`.md`/`.markdown` only)
416
+
416
417
  ### Using Tags for Filtering
417
418
 
418
419
  ```bash
419
420
  # Delete all instruction documents
420
- uvx rosetta-cli@latest cleanup-dataset --prefix "[instructions]"
421
+ uvx rosetta-cli@latest cleanup-dataset --tags "instructions"
421
422
 
422
- # Delete all r1 agent documents
423
- uvx rosetta-cli@latest cleanup-dataset --prefix "[instructions][agents][r1]"
423
+ # Delete documents tagged "agents" OR "r1"
424
+ uvx rosetta-cli@latest cleanup-dataset --tags "agents,r1"
424
425
  ```
425
426
 
427
+ Use `--prefix` for literal title-prefix matching instead, e.g. `--prefix "core/skills"`.
428
+
426
429
  ## 💻 Usage Examples
427
430
 
428
431
  ### Example 1: First-Time Setup
@@ -549,10 +552,11 @@ nano .env
549
552
 
550
553
  ### Documents Not Showing Tags
551
554
 
552
- Tags should appear in title with format `[tag1][tag2]`:
555
+ Tags live in metadata, not in the title. `list-dataset` prints them on their own line:
553
556
  ```bash
554
557
  uvx rosetta-cli@latest list-dataset
555
- # Output: 1. [instructions][agents][r1] agents.md
558
+ # Output: 1. agents.md
559
+ # Tags: instructions, agents, r1, agents.md
556
560
  ```
557
561
 
558
562
  ## 🚦 Performance Tips
@@ -591,7 +595,7 @@ RAGFLOW_CHUNK_TOKEN_NUM=1024
591
595
 
592
596
  ```bash
593
597
  # Fast: Delete specific documents
594
- uvx rosetta-cli@latest cleanup-dataset --prefix "[instructions][agents]" --force
598
+ uvx rosetta-cli@latest cleanup-dataset --tags "agents" --force
595
599
 
596
600
  # Slow: Delete and republish everything
597
601
  uvx rosetta-cli@latest cleanup-dataset --force
File without changes
File without changes