Merge remote-tracking branch 'origin/main' into canary

This commit is contained in:
lobehubbot
2026-03-16 03:49:09 +00:00
8 changed files with 13143 additions and 1 deletions

View File

@@ -2,6 +2,31 @@
# Changelog
### [Version 2.1.42](https://github.com/lobehub/lobe-chat/compare/v2.1.41...v2.1.42)
<sup>Released on **2026-03-14**</sup>
#### 🐛 Bug Fixes
- **ci**: create stable update manifests for S3 publish.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **ci**: create stable update manifests for S3 publish, closes [#12974](https://github.com/lobehub/lobe-chat/issues/12974) ([9bb9222](https://github.com/lobehub/lobe-chat/commit/9bb9222))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 2.1.40](https://github.com/lobehub/lobe-chat/compare/v2.1.39...v2.1.40)
<sup>Released on **2026-03-12**</sup>

View File

@@ -1,4 +1,9 @@
[
{
"children": {},
"date": "2026-03-14",
"version": "2.1.42"
},
{
"children": {
"improvements": [

View File

@@ -1,6 +1,6 @@
{
"name": "@lobehub/lobehub",
"version": "2.1.41",
"version": "2.1.42",
"description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
"keywords": [
"framework",

View File

@@ -0,0 +1,50 @@
CREATE TABLE IF NOT EXISTS "agent_documents" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"user_id" text NOT NULL,
"agent_id" text NOT NULL,
"document_id" varchar(255) NOT NULL,
"template_id" varchar(100),
"access_self" integer DEFAULT 31 NOT NULL,
"access_shared" integer DEFAULT 0 NOT NULL,
"access_public" integer DEFAULT 0 NOT NULL,
"policy_load" varchar(30) DEFAULT 'always' NOT NULL,
"policy" jsonb,
"policy_load_position" varchar(50) DEFAULT 'before-first-user' NOT NULL,
"policy_load_format" varchar(20) DEFAULT 'raw' NOT NULL,
"policy_load_rule" varchar(50) DEFAULT 'always' NOT NULL,
"deleted_at" timestamp with time zone,
"deleted_by_user_id" text,
"deleted_by_agent_id" text,
"delete_reason" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "agent_documents" DROP CONSTRAINT IF EXISTS "agent_documents_user_id_users_id_fk";--> statement-breakpoint
ALTER TABLE "agent_documents" ADD CONSTRAINT "agent_documents_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "agent_documents" DROP CONSTRAINT IF EXISTS "agent_documents_agent_id_agents_id_fk";--> statement-breakpoint
ALTER TABLE "agent_documents" ADD CONSTRAINT "agent_documents_agent_id_agents_id_fk" FOREIGN KEY ("agent_id") REFERENCES "public"."agents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "agent_documents" DROP CONSTRAINT IF EXISTS "agent_documents_document_id_documents_id_fk";--> statement-breakpoint
ALTER TABLE "agent_documents" ADD CONSTRAINT "agent_documents_document_id_documents_id_fk" FOREIGN KEY ("document_id") REFERENCES "public"."documents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "agent_documents" DROP CONSTRAINT IF EXISTS "agent_documents_deleted_by_user_id_users_id_fk";--> statement-breakpoint
ALTER TABLE "agent_documents" ADD CONSTRAINT "agent_documents_deleted_by_user_id_users_id_fk" FOREIGN KEY ("deleted_by_user_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "agent_documents" DROP CONSTRAINT IF EXISTS "agent_documents_deleted_by_agent_id_agents_id_fk";--> statement-breakpoint
ALTER TABLE "agent_documents" ADD CONSTRAINT "agent_documents_deleted_by_agent_id_agents_id_fk" FOREIGN KEY ("deleted_by_agent_id") REFERENCES "public"."agents"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_user_id_idx" ON "agent_documents" USING btree ("user_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_agent_id_idx" ON "agent_documents" USING btree ("agent_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_access_self_idx" ON "agent_documents" USING btree ("access_self");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_access_shared_idx" ON "agent_documents" USING btree ("access_shared");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_access_public_idx" ON "agent_documents" USING btree ("access_public");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_policy_load_idx" ON "agent_documents" USING btree ("policy_load");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_template_id_idx" ON "agent_documents" USING btree ("template_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_policy_load_position_idx" ON "agent_documents" USING btree ("policy_load_position");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_policy_load_format_idx" ON "agent_documents" USING btree ("policy_load_format");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_policy_load_rule_idx" ON "agent_documents" USING btree ("policy_load_rule");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_agent_load_position_idx" ON "agent_documents" USING btree ("agent_id","policy_load_position");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_deleted_at_idx" ON "agent_documents" USING btree ("deleted_at");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_agent_autoload_deleted_idx" ON "agent_documents" USING btree ("agent_id","deleted_at","policy_load");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "agent_documents_document_id_idx" ON "agent_documents" USING btree ("document_id");--> statement-breakpoint
CREATE UNIQUE INDEX IF NOT EXISTS "agent_documents_agent_document_user_unique" ON "agent_documents" USING btree ("agent_id","document_id","user_id");

File diff suppressed because it is too large Load Diff

View File

@@ -644,6 +644,13 @@
"when": 1773308533505,
"tag": "0091_topics_add_description",
"breakpoints": true
},
{
"idx": 92,
"version": "7",
"when": 1773419250145,
"tag": "0092_add_agent_documents",
"breakpoints": true
}
],
"version": "6"

View File

@@ -0,0 +1,183 @@
import {
index,
integer,
jsonb,
pgTable,
text,
uniqueIndex,
uuid,
varchar,
} from 'drizzle-orm/pg-core';
import { createdAt, timestamptz, updatedAt } from './_helpers';
import { agents } from './agent';
import { documents } from './file';
import { users } from './user';
/**
* Agent document settings mapped to canonical documents rows.
*
* Access model (5-bit bitmask):
* - bit4 (16): delete
* - bit3 (8): list
* - bit2 (4): write
* - bit1 (2): read
* - bit0 (1): execute
* - full access: 31, no access: 0
*
* Access domains:
* - accessSelf: owner/self channel access
* - accessShared: shared users/agents channel access
* - accessPublic: public channel access
*
* Policy load:
* - policyLoad controls injection pipeline participation (enum-like string values).
* - deletedAt/deletedByUserId/deletedByAgentId/deleteReason implement soft delete.
*
* User actions:
* - Disable document:
* 1) set accessSelf/accessShared/accessPublic to 0 as needed
* 2) set policyLoad = 'disabled'
* 3) keep deletedAt = null (still restorable as active record)
* - Enable document:
* 1) restore access bitmask (example: 10 => list + read)
* 2) set policyLoad = 'always'
* 3) ensure deletedAt = null
* - Delete document:
* 1) set deletedAt + one of deletedByUserId/deletedByAgentId + deleteReason
* 2) force policyLoad = 'disabled'
* 3) keep row for recovery/audit
*/
export const agentDocuments = pgTable(
'agent_documents',
{
id: uuid('id').primaryKey().defaultRandom(),
userId: text('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
agentId: text('agent_id')
.notNull()
.references(() => agents.id, { onDelete: 'cascade' }),
documentId: varchar('document_id', { length: 255 })
.notNull()
.references(() => documents.id, { onDelete: 'cascade' }),
/**
* Template source label (e.g. 'claw', 'custom').
* Used for grouping and re-initialization workflows.
*/
templateId: varchar('template_id', { length: 100 }),
/**
* Access bitmask for owner/self channel.
*
* Bit positions (b4 b3 b2 b1 b0):
* - b4 (1 << 4 = 16): delete
* - b3 (1 << 3 = 8): list
* - b2 (1 << 2 = 4): write
* - b1 (1 << 1 = 2): read
* - b0 (1 << 0 = 1): execute
*
* Examples:
* - 00000b = 0 => no permissions
* - 01010b = 10 => list + read
* - 11111b = 31 => full permissions (default)
*
* Shared-access profile examples:
* - locked prompt: accessSelf=10, accessShared=10, accessPublic=0
* - executable skill: accessSelf=31, accessShared=15, accessPublic=0
* - public reference doc: accessSelf=31, accessShared=10, accessPublic=10
*/
accessSelf: integer('access_self').notNull().default(31),
/**
* Access bitmask for shared channel (shared users/agents).
* Same 5-bit semantics as accessSelf.
*/
accessShared: integer('access_shared').notNull().default(0),
/**
* Access bitmask for public channel.
* Same 5-bit semantics as accessSelf.
*/
accessPublic: integer('access_public').notNull().default(0),
/**
* Controls whether this document participates in automatic context injection.
* Example values: 'always', 'disabled'. Keep enum values unchanged.
* This is independent from access bitmask values.
*/
policyLoad: varchar('policy_load', { length: 30 }).notNull().default('always'),
/**
* Canonical behavior config for context/retrieval policy.
* Keep extensible fields here.
*/
policy: jsonb('policy').$type<Record<string, any>>(),
/**
* Indexed projection of policy.context.position for fast filtering/sorting.
*/
policyLoadPosition: varchar('policy_load_position', { length: 50 })
.notNull()
.default('before-first-user'),
/**
* Indexed projection of policy.context.policyLoadFormat for rendering strategy.
* Example values: 'raw', 'file'.
*/
policyLoadFormat: varchar('policy_load_format', { length: 20 }).notNull().default('raw'),
/**
* Indexed projection of policy.context.rule for fast filtering.
*/
policyLoadRule: varchar('policy_load_rule', { length: 50 }).notNull().default('always'),
/**
* Soft delete timestamp. Non-null means logically deleted.
*/
deletedAt: timestamptz('deleted_at'),
/**
* User actor who performed soft delete.
*/
deletedByUserId: text('deleted_by_user_id').references(() => users.id, {
onDelete: 'set null',
}),
/**
* Agent actor who performed soft delete.
*/
deletedByAgentId: text('deleted_by_agent_id').references(() => agents.id, {
onDelete: 'set null',
}),
/**
* Optional operator-supplied reason for deletion.
*/
deleteReason: text('delete_reason'),
createdAt: createdAt(),
updatedAt: updatedAt(),
},
(table) => [
index('agent_documents_user_id_idx').on(table.userId),
index('agent_documents_agent_id_idx').on(table.agentId),
index('agent_documents_access_self_idx').on(table.accessSelf),
index('agent_documents_access_shared_idx').on(table.accessShared),
index('agent_documents_access_public_idx').on(table.accessPublic),
index('agent_documents_policy_load_idx').on(table.policyLoad),
index('agent_documents_template_id_idx').on(table.templateId),
index('agent_documents_policy_load_position_idx').on(table.policyLoadPosition),
index('agent_documents_policy_load_format_idx').on(table.policyLoadFormat),
index('agent_documents_policy_load_rule_idx').on(table.policyLoadRule),
index('agent_documents_agent_load_position_idx').on(table.agentId, table.policyLoadPosition),
index('agent_documents_deleted_at_idx').on(table.deletedAt),
index('agent_documents_agent_autoload_deleted_idx').on(
table.agentId,
table.deletedAt,
table.policyLoad,
),
index('agent_documents_document_id_idx').on(table.documentId),
uniqueIndex('agent_documents_agent_document_user_unique').on(
table.agentId,
table.documentId,
table.userId,
),
],
);
export type AgentDocument = typeof agentDocuments.$inferSelect;
export type NewAgentDocument = typeof agentDocuments.$inferInsert;

View File

@@ -1,6 +1,7 @@
export * from './agent';
export * from './agentBotProvider';
export * from './agentCronJob';
export * from './agentDocuments';
export * from './agentEvals';
export * from './agentSkill';
export * from './aiInfra';