@palettelab/cli 0.3.33 → 0.3.34
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/README.md +45 -0
- package/docs/python-backend-sdk.md +133 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -509,6 +509,51 @@ management. For advanced Qdrant features, use `ctx.vector.client()` with
|
|
|
509
509
|
`collection_name()`, `scoped_filter()`, `merge_filter()`, `scoped_payload()`,
|
|
510
510
|
and `scoped_point()` so custom calls remain scoped.
|
|
511
511
|
|
|
512
|
+
Common managed-service commands:
|
|
513
|
+
|
|
514
|
+
```python
|
|
515
|
+
# Redis strings, counters, and key discovery
|
|
516
|
+
await ctx.redis.get("key", default=None)
|
|
517
|
+
await ctx.redis.set("key", {"json": True}, ttl=600)
|
|
518
|
+
await ctx.redis.delete("key1", "key2")
|
|
519
|
+
await ctx.redis.exists("key")
|
|
520
|
+
await ctx.redis.expire("key", 300)
|
|
521
|
+
await ctx.redis.ttl("key")
|
|
522
|
+
await ctx.redis.incr("counter")
|
|
523
|
+
await ctx.redis.decr("counter")
|
|
524
|
+
await ctx.redis.scan(prefix="cache:", limit=100)
|
|
525
|
+
|
|
526
|
+
# Redis hashes, lists, sets, sorted sets, streams, locks
|
|
527
|
+
await ctx.redis.hset("hash", "field", {"value": 1})
|
|
528
|
+
await ctx.redis.hgetall("hash")
|
|
529
|
+
await ctx.redis.lpush("queue", {"job": 1})
|
|
530
|
+
await ctx.redis.lrange("queue", 0, -1)
|
|
531
|
+
await ctx.redis.sadd("tags", "red", "blue")
|
|
532
|
+
await ctx.redis.smembers("tags")
|
|
533
|
+
await ctx.redis.zadd("scores", {"alice": 10})
|
|
534
|
+
await ctx.redis.zrange("scores", 0, -1, with_scores=True)
|
|
535
|
+
await ctx.redis.xadd("events", {"type": "created"})
|
|
536
|
+
await ctx.redis.xread({"events": "0-0"}, count=10)
|
|
537
|
+
await ctx.redis.lock("invoice:1", token, ttl=30)
|
|
538
|
+
await ctx.redis.unlock("invoice:1", token)
|
|
539
|
+
|
|
540
|
+
# Redis provider-style data-plane calls
|
|
541
|
+
await ctx.redis.execute("MSET", "a", "1", "b", "2")
|
|
542
|
+
values = await ctx.redis.execute("MGET", "a", "b")
|
|
543
|
+
|
|
544
|
+
# Vector search
|
|
545
|
+
await ctx.vector.upsert_texts("knowledge", [{"id": "doc-1", "text": "Text"}])
|
|
546
|
+
await ctx.vector.upsert_vectors("knowledge", [{"id": "vec-1", "vector": [0.1, 0.2]}])
|
|
547
|
+
hits = await ctx.vector.search("knowledge", query="invoice policy", top_k=10)
|
|
548
|
+
record = await ctx.vector.get("knowledge", "doc-1")
|
|
549
|
+
await ctx.vector.delete("knowledge", ["doc-1"])
|
|
550
|
+
await ctx.vector.delete_index("knowledge")
|
|
551
|
+
stats = await ctx.vector.stats("knowledge")
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
Blocked Redis control-plane commands include `FLUSHDB`, `FLUSHALL`, `CONFIG`,
|
|
555
|
+
`KEYS`, `CLUSTER`, `SCRIPT`, `EVAL`, `FUNCTION`, and `SELECT`.
|
|
556
|
+
|
|
512
557
|
### `pltt login`
|
|
513
558
|
|
|
514
559
|
Save a Palette sandbox or production environment URL plus token in `~/.palette/config.json` with file mode `0600`. Environment variables still override the stored token when present.
|
|
@@ -344,6 +344,52 @@ Alembic migrations. Route code intentionally has data permissions only; it
|
|
|
344
344
|
cannot access Palette core tables, another app's schema, or another org's
|
|
345
345
|
RLS-protected rows.
|
|
346
346
|
|
|
347
|
+
Common `ctx.db` operations:
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
from sqlalchemy import delete, func, insert, select, text, update
|
|
351
|
+
|
|
352
|
+
rows = (await ctx.db.execute(select(Invoice))).scalars().all()
|
|
353
|
+
invoice = await ctx.db.scalar(select(Invoice).where(Invoice.id == invoice_id))
|
|
354
|
+
count = await ctx.db.scalar(select(func.count()).select_from(Invoice))
|
|
355
|
+
|
|
356
|
+
ctx.db.add(Invoice(customer_name="A", amount=10, status="draft"))
|
|
357
|
+
ctx.db.add_all([
|
|
358
|
+
Invoice(customer_name="B", amount=20, status="draft"),
|
|
359
|
+
Invoice(customer_name="C", amount=30, status="draft"),
|
|
360
|
+
])
|
|
361
|
+
await ctx.db.execute(insert(Invoice).values(customer_name="D", amount=40, status="draft"))
|
|
362
|
+
await ctx.db.execute(update(Invoice).where(Invoice.id == invoice_id).values(status="paid"))
|
|
363
|
+
await ctx.db.execute(delete(Invoice).where(Invoice.id == invoice_id))
|
|
364
|
+
|
|
365
|
+
async with ctx.db.begin():
|
|
366
|
+
ctx.db.add(Invoice(customer_name="E", amount=50, status="queued"))
|
|
367
|
+
|
|
368
|
+
await ctx.db.commit()
|
|
369
|
+
await ctx.db.rollback()
|
|
370
|
+
await ctx.db.refresh(invoice)
|
|
371
|
+
|
|
372
|
+
result = await ctx.db.execute(
|
|
373
|
+
text("select id, customer_name from finance_tools__invoices where amount > :amount"),
|
|
374
|
+
{"amount": 100},
|
|
375
|
+
)
|
|
376
|
+
rows = result.mappings().all()
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Common migration operations:
|
|
380
|
+
|
|
381
|
+
```python
|
|
382
|
+
op.create_table(...)
|
|
383
|
+
op.add_column(...)
|
|
384
|
+
op.alter_column(...)
|
|
385
|
+
op.create_index(...)
|
|
386
|
+
op.create_unique_constraint(...)
|
|
387
|
+
op.create_foreign_key(...)
|
|
388
|
+
op.drop_index(...)
|
|
389
|
+
op.drop_column(...)
|
|
390
|
+
ensure_org_rls(op, "finance_tools__invoices")
|
|
391
|
+
```
|
|
392
|
+
|
|
347
393
|
## 8. Data Rooms From Python
|
|
348
394
|
|
|
349
395
|
Use `ctx.data_rooms` when backend code needs to create folders, find files, or
|
|
@@ -569,6 +615,93 @@ while blocking server/admin commands. `ctx.vector.client()` returns the Qdrant
|
|
|
569
615
|
client for custom calls; combine it with `collection_name()`, `scoped_filter()`,
|
|
570
616
|
`merge_filter()`, `scoped_payload()`, and `scoped_point()` to preserve isolation.
|
|
571
617
|
|
|
618
|
+
Common `ctx.redis` commands:
|
|
619
|
+
|
|
620
|
+
```python
|
|
621
|
+
await ctx.redis.get("key", default=None)
|
|
622
|
+
await ctx.redis.set("key", {"json": True}, ttl=600, nx=False, xx=False)
|
|
623
|
+
await ctx.redis.delete("key1", "key2")
|
|
624
|
+
await ctx.redis.exists("key")
|
|
625
|
+
await ctx.redis.expire("key", 300)
|
|
626
|
+
await ctx.redis.ttl("key")
|
|
627
|
+
await ctx.redis.incr("counter", 1)
|
|
628
|
+
await ctx.redis.decr("counter", 1)
|
|
629
|
+
await ctx.redis.scan(prefix="cache:", limit=100)
|
|
630
|
+
|
|
631
|
+
await ctx.redis.hset("hash", "field", {"value": 1})
|
|
632
|
+
await ctx.redis.hget("hash", "field")
|
|
633
|
+
await ctx.redis.hgetall("hash")
|
|
634
|
+
await ctx.redis.hdel("hash", "field")
|
|
635
|
+
|
|
636
|
+
await ctx.redis.lpush("queue", {"job": 1})
|
|
637
|
+
await ctx.redis.rpush("queue", {"job": 2})
|
|
638
|
+
await ctx.redis.lpop("queue")
|
|
639
|
+
await ctx.redis.rpop("queue")
|
|
640
|
+
await ctx.redis.lrange("queue", 0, -1)
|
|
641
|
+
|
|
642
|
+
await ctx.redis.sadd("tags", "red", "blue")
|
|
643
|
+
await ctx.redis.smembers("tags")
|
|
644
|
+
await ctx.redis.srem("tags", "red")
|
|
645
|
+
|
|
646
|
+
await ctx.redis.zadd("scores", {"alice": 10, "bob": 8})
|
|
647
|
+
await ctx.redis.zrange("scores", 0, -1, with_scores=True)
|
|
648
|
+
await ctx.redis.zrem("scores", "bob")
|
|
649
|
+
|
|
650
|
+
await ctx.redis.enqueue("jobs", {"task": "sync"})
|
|
651
|
+
await ctx.redis.dequeue("jobs")
|
|
652
|
+
await ctx.redis.xadd("events", {"type": "created"})
|
|
653
|
+
await ctx.redis.xread({"events": "0-0"}, count=10)
|
|
654
|
+
await ctx.redis.lock("invoice:1", token, ttl=30)
|
|
655
|
+
await ctx.redis.unlock("invoice:1", token)
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
Provider-style Redis commands:
|
|
659
|
+
|
|
660
|
+
```python
|
|
661
|
+
await ctx.redis.execute("MSET", "a", "1", "b", "2")
|
|
662
|
+
values = await ctx.redis.execute("MGET", "a", "b")
|
|
663
|
+
await ctx.redis.execute("ZUNIONSTORE", "dest", 2, "scores:1", "scores:2")
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
Server/admin Redis commands are blocked because they would affect the shared
|
|
667
|
+
central Redis instance: `FLUSHDB`, `FLUSHALL`, `CONFIG`, `KEYS`, `CLUSTER`,
|
|
668
|
+
`SCRIPT`, `EVAL`, `FUNCTION`, `SELECT`, and similar control-plane commands.
|
|
669
|
+
|
|
670
|
+
Common `ctx.vector` commands:
|
|
671
|
+
|
|
672
|
+
```python
|
|
673
|
+
await ctx.vector.upsert_texts(
|
|
674
|
+
"knowledge",
|
|
675
|
+
[{"id": "doc-1", "text": "Text to embed", "metadata": {"type": "note"}}],
|
|
676
|
+
)
|
|
677
|
+
await ctx.vector.upsert_vectors(
|
|
678
|
+
"knowledge",
|
|
679
|
+
[{"id": "vec-1", "vector": [0.1, 0.2], "metadata": {"type": "manual"}}],
|
|
680
|
+
)
|
|
681
|
+
hits = await ctx.vector.search("knowledge", query="invoice policy", top_k=10)
|
|
682
|
+
hits = await ctx.vector.search("knowledge", vector=[0.1, 0.2], filter={"type": "note"})
|
|
683
|
+
record = await ctx.vector.get("knowledge", "doc-1")
|
|
684
|
+
await ctx.vector.delete("knowledge", ["doc-1"])
|
|
685
|
+
await ctx.vector.delete_index("knowledge")
|
|
686
|
+
stats = await ctx.vector.stats("knowledge")
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
Advanced Qdrant calls should use scoped helpers:
|
|
690
|
+
|
|
691
|
+
```python
|
|
692
|
+
client = await ctx.vector.client()
|
|
693
|
+
collection = ctx.vector.collection_name()
|
|
694
|
+
query_filter = ctx.vector.scoped_filter("knowledge", {"type": "note"})
|
|
695
|
+
point = ctx.vector.scoped_point(
|
|
696
|
+
"knowledge",
|
|
697
|
+
id="doc-2",
|
|
698
|
+
vector=[0.1, 0.2],
|
|
699
|
+
text="Indexed text",
|
|
700
|
+
metadata={"type": "note"},
|
|
701
|
+
)
|
|
702
|
+
await client.upsert(collection_name=collection, points=[point])
|
|
703
|
+
```
|
|
704
|
+
|
|
572
705
|
## 10. Lifecycle Hooks
|
|
573
706
|
|
|
574
707
|
Lifecycle hooks let an app seed defaults or clean up app-owned data when the
|