@fenixforce/edition-mobile 0.1.0 → 0.1.1
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/dist/index.js +405 -27
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,4 +1,382 @@
|
|
|
1
|
-
|
|
1
|
+
var ar=Object.defineProperty;var ve=(t,e)=>()=>(t&&(e=t(t=0)),e);var cr=(t,e)=>{for(var r in e)ar(t,r,{get:e[r],enumerable:!0})};import*as Eo from"pg";function St(t){return{id:t.id,conversationId:t.conversation_id,userId:t.user_id,role:t.role,content:t.content,channel:t.channel,tokenCount:t.token_count??null,metadata:t.metadata??{},createdAt:new Date(t.created_at)}}function Rn(t){return{id:t.id,userId:t.user_id,title:t.title??null,channel:t.channel,metadata:t.metadata??{},createdAt:new Date(t.created_at),updatedAt:new Date(t.updated_at)}}function In(t){return{id:t.id,userId:t.user_id,content:t.content,category:t.category,embedding:t.embedding?Ln(t.embedding):null,heat:t.heat,accessCount:t.access_count,lastAccessedAt:new Date(t.last_accessed_at),createdAt:new Date(t.created_at),updatedAt:new Date(t.updated_at)}}function _n(t){return{userId:t.user_id,summary:t.summary,updatedAt:new Date(t.updated_at)}}function Pn(t){return{id:t.id,userId:t.user_id,conversationId:t.conversation_id??null,content:t.content,category:t.category,reviewed:t.reviewed,createdAt:new Date(t.created_at),reviewedAt:t.reviewed_at?new Date(t.reviewed_at):null}}function Mn(t){return{id:t.id,conversationId:t.conversation_id,artifactType:t.artifact_type,title:t.title,content:t.content,metadata:t.metadata??{},createdAt:new Date(t.created_at),updatedAt:new Date(t.updated_at)}}function Nn(t){return{id:t.id,userId:t.user_id,conversationId:t.conversation_id??null,provider:t.provider,model:t.model,inputTokens:t.input_tokens,outputTokens:t.output_tokens,costUsd:t.cost_usd,createdAt:new Date(t.created_at)}}function de(t){return{id:t.id,type:t.type,status:t.status,priority:t.priority,payload:t.payload??{},result:t.result??null,error:t.error??null,attempts:t.attempts,maxAttempts:t.max_attempts,claimedAt:t.claimed_at?new Date(t.claimed_at):null,completedAt:t.completed_at?new Date(t.completed_at):null,createdAt:new Date(t.created_at),updatedAt:new Date(t.updated_at)}}function Ce(t){return{id:t.id,userId:t.user_id,sourceType:t.source_type,uri:t.uri,status:t.status,metadata:t.metadata??{},createdAt:new Date(t.created_at),updatedAt:new Date(t.updated_at)}}function xt(t){return{id:t.id,sourceId:t.source_id,content:t.content,embedding:t.embedding?Ln(t.embedding):null,chunkIndex:t.chunk_index,metadata:t.metadata??{},createdAt:new Date(t.created_at)}}function wt(t){return{id:t.id,userId:t.user_id,provider:t.provider,encryptedData:t.encrypted_data,iv:t.iv,authTag:t.auth_tag,createdAt:new Date(t.created_at),updatedAt:new Date(t.updated_at)}}function Ct(t){return{id:t.id,workspaceId:t.workspace_id,fileName:t.file_name,content:t.content,metadata:t.metadata??{},createdAt:new Date(t.created_at),updatedAt:new Date(t.updated_at)}}function Ln(t){return Array.isArray(t)?t:typeof t=="string"?t.replace(/^\[|\]$/g,"").split(",").map(Number):[]}function Ae(t){return`[${t.join(",")}]`}function ue(t){let e=new ko({connectionString:t.connectionString,max:t.max??20});return{async initialize(){let n=await e.connect();try{await n.query(So),console.log("[kernel/storage] PostgreSQL migration complete")}finally{n.release()}},async close(){await e.end()},async saveMessage(n){let{rows:o}=await e.query(`INSERT INTO messages (conversation_id, user_id, role, content, channel, token_count, metadata)
|
|
2
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
3
|
+
RETURNING *`,[n.conversationId,n.userId,n.role,n.content,n.channel,n.tokenCount,JSON.stringify(n.metadata)]);return St(o[0])},async getMessagesByConversation(n,o=50){let{rows:s}=await e.query("SELECT * FROM messages WHERE conversation_id = $1 ORDER BY created_at ASC LIMIT $2",[n,o]);return s.map(St)},async getMessageById(n){let{rows:o}=await e.query("SELECT * FROM messages WHERE id = $1",[n]);return o[0]?St(o[0]):null},async createConversation(n){let{rows:o}=await e.query(`INSERT INTO conversations (user_id, title, channel, metadata)
|
|
4
|
+
VALUES ($1, $2, $3, $4)
|
|
5
|
+
RETURNING *`,[n.userId,n.title,n.channel,JSON.stringify(n.metadata)]);return Rn(o[0])},async listConversations(n,o){let s=o?.limit??50,i=o?.offset??0,{rows:a}=await e.query("SELECT * FROM conversations WHERE user_id = $1 ORDER BY updated_at DESC LIMIT $2 OFFSET $3",[n,s,i]);return a.map(Rn)},async deleteConversation(n){await e.query("DELETE FROM conversations WHERE id = $1",[n])},async saveMemorySegment(n){let o=n.embedding?Ae(n.embedding):null,{rows:s}=await e.query(`INSERT INTO memory_segments (user_id, content, category, embedding, heat)
|
|
6
|
+
VALUES ($1, $2, $3, $4::vector, $5)
|
|
7
|
+
RETURNING *`,[n.userId,n.content,n.category,o,n.heat]);return In(s[0])},async searchMemoryByEmbedding(n,o,s=10){let i=Ae(o),{rows:a}=await e.query(`SELECT *, 1 - (embedding <=> $2::vector) AS score
|
|
8
|
+
FROM memory_segments
|
|
9
|
+
WHERE user_id = $1 AND embedding IS NOT NULL
|
|
10
|
+
ORDER BY embedding <=> $2::vector
|
|
11
|
+
LIMIT $3`,[n,i,s]);return a.map(c=>({segment:In(c),score:c.score}))},async getProfile(n){let{rows:o}=await e.query("SELECT * FROM user_profiles WHERE user_id = $1",[n]);return o[0]?_n(o[0]):null},async upsertProfile(n,o){let{rows:s}=await e.query(`INSERT INTO user_profiles (user_id, summary, updated_at)
|
|
12
|
+
VALUES ($1, $2, now())
|
|
13
|
+
ON CONFLICT (user_id) DO UPDATE SET summary = $2, updated_at = now()
|
|
14
|
+
RETURNING *`,[n,o]);return _n(s[0])},async updateHeatScores(n,o){n.length!==0&&await e.query(`UPDATE memory_segments
|
|
15
|
+
SET heat = heat + $2, access_count = access_count + 1, last_accessed_at = now()
|
|
16
|
+
WHERE id = ANY($1)`,[n,o])},async saveObservation(n){let{rows:o}=await e.query(`INSERT INTO observations (user_id, conversation_id, content, category)
|
|
17
|
+
VALUES ($1, $2, $3, $4)
|
|
18
|
+
RETURNING *`,[n.userId,n.conversationId,n.content,n.category]);return Pn(o[0])},async listPendingObservations(n,o){let s=o?.limit??50,i=o?.offset??0,{rows:a}=await e.query(`SELECT * FROM observations
|
|
19
|
+
WHERE user_id = $1 AND NOT reviewed
|
|
20
|
+
ORDER BY created_at DESC
|
|
21
|
+
LIMIT $2 OFFSET $3`,[n,s,i]);return a.map(Pn)},async markObservationReviewed(n){await e.query("UPDATE observations SET reviewed = TRUE, reviewed_at = now() WHERE id = $1",[n])},async saveBrainArtifact(n){let{rows:o}=await e.query(`INSERT INTO brain_artifacts (conversation_id, artifact_type, title, content, metadata)
|
|
22
|
+
VALUES ($1, $2, $3, $4, $5)
|
|
23
|
+
RETURNING *`,[n.conversationId,n.artifactType,n.title,n.content,JSON.stringify(n.metadata)]);return Mn(o[0])},async loadBrainArtifacts(n){let{rows:o}=await e.query("SELECT * FROM brain_artifacts WHERE conversation_id = $1 ORDER BY created_at ASC",[n]);return o.map(Mn)},async deleteBrainArtifact(n){await e.query("DELETE FROM brain_artifacts WHERE id = $1",[n])},async insertCostLog(n){let{rows:o}=await e.query(`INSERT INTO cost_logs (user_id, conversation_id, provider, model, input_tokens, output_tokens, cost_usd)
|
|
24
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
25
|
+
RETURNING *`,[n.userId,n.conversationId,n.provider,n.model,n.inputTokens,n.outputTokens,n.costUsd]);return Nn(o[0])},async queryCostLogs(n){let{rows:o}=await e.query(`SELECT * FROM cost_logs
|
|
26
|
+
WHERE user_id = $1 AND created_at >= $2 AND created_at <= $3
|
|
27
|
+
ORDER BY created_at DESC`,[n.userId,n.startDate,n.endDate]);return o.map(Nn)},async createJob(n){let{rows:o}=await e.query(`INSERT INTO jobs (type, priority, payload, max_attempts)
|
|
28
|
+
VALUES ($1, $2, $3, $4)
|
|
29
|
+
RETURNING *`,[n.type,n.priority,JSON.stringify(n.payload),n.maxAttempts]);return de(o[0])},async claimNextJob(n){let o=n&&n.length>0?"AND type = ANY($1)":"",s=n&&n.length>0?[n]:[],{rows:i}=await e.query(`UPDATE jobs
|
|
30
|
+
SET status = 'running', claimed_at = now(), attempts = attempts + 1, updated_at = now()
|
|
31
|
+
WHERE id = (
|
|
32
|
+
SELECT id FROM jobs
|
|
33
|
+
WHERE status = 'pending' ${o}
|
|
34
|
+
ORDER BY priority DESC, created_at ASC
|
|
35
|
+
LIMIT 1
|
|
36
|
+
FOR UPDATE SKIP LOCKED
|
|
37
|
+
)
|
|
38
|
+
RETURNING *`,s);return i[0]?de(i[0]):null},async updateJobStatus(n,o,s,i){let a=o==="completed"||o==="failed"||o==="dead"?"now()":"NULL",{rows:c}=await e.query(`UPDATE jobs
|
|
39
|
+
SET status = $2,
|
|
40
|
+
result = $3,
|
|
41
|
+
error = $4,
|
|
42
|
+
completed_at = ${a==="now()"?"now()":"completed_at"},
|
|
43
|
+
updated_at = now()
|
|
44
|
+
WHERE id = $1
|
|
45
|
+
RETURNING *`,[n,o,s?JSON.stringify(s):null,i??null]);return de(c[0])},async getJobById(n){let{rows:o}=await e.query("SELECT * FROM jobs WHERE id = $1",[n]);return o[0]?de(o[0]):null},async listJobs(n,o){let s=[],i=[],a=1;n.status&&(s.push(`status = $${a++}`),i.push(n.status)),n.type&&(s.push(`type = $${a++}`),i.push(n.type));let c=s.length>0?`WHERE ${s.join(" AND ")}`:"",l=o?.limit??50,d=o?.offset??0;i.push(l,d);let{rows:u}=await e.query(`SELECT * FROM jobs ${c} ORDER BY created_at DESC LIMIT $${a++} OFFSET $${a}`,i);return u.map(de)},async markDeadJobs(n){let{rowCount:o}=await e.query(`UPDATE jobs
|
|
46
|
+
SET status = 'dead', updated_at = now(), completed_at = now()
|
|
47
|
+
WHERE status = 'running'
|
|
48
|
+
AND claimed_at < now() - ($1 || ' seconds')::interval`,[n]);return o??0},async createContentSource(n){let{rows:o}=await e.query(`INSERT INTO content_sources (user_id, source_type, uri, status, metadata)
|
|
49
|
+
VALUES ($1, $2, $3, $4, $5)
|
|
50
|
+
RETURNING *`,[n.userId,n.sourceType,n.uri,n.status,JSON.stringify(n.metadata)]);return Ce(o[0])},async updateContentSourceStatus(n,o){let{rows:s}=await e.query("UPDATE content_sources SET status = $2, updated_at = now() WHERE id = $1 RETURNING *",[n,o]);return Ce(s[0])},async getContentSourceById(n){let{rows:o}=await e.query("SELECT * FROM content_sources WHERE id = $1",[n]);return o[0]?Ce(o[0]):null},async listContentSources(n,o){let s=o?.limit??50,i=o?.offset??0,{rows:a}=await e.query("SELECT * FROM content_sources WHERE user_id = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3",[n,s,i]);return a.map(Ce)},async bulkInsertContentChunks(n){if(n.length===0)return[];let o=[],s=[],i=1;for(let c of n){let l=c.embedding?Ae(c.embedding):null;o.push(`($${i++}, $${i++}, $${i++}::vector, $${i++}, $${i++})`),s.push(c.sourceId,c.content,l,c.chunkIndex,JSON.stringify(c.metadata))}let{rows:a}=await e.query(`INSERT INTO content_chunks (source_id, content, embedding, chunk_index, metadata)
|
|
51
|
+
VALUES ${o.join(", ")}
|
|
52
|
+
RETURNING *`,s);return a.map(xt)},async searchContentChunksByEmbedding(n,o,s=10){if(n.length===0)return[];let i=Ae(o),{rows:a}=await e.query(`SELECT *, 1 - (embedding <=> $2::vector) AS score
|
|
53
|
+
FROM content_chunks
|
|
54
|
+
WHERE source_id = ANY($1) AND embedding IS NOT NULL
|
|
55
|
+
ORDER BY embedding <=> $2::vector
|
|
56
|
+
LIMIT $3`,[n,i,s]);return a.map(c=>({chunk:xt(c),score:c.score}))},async searchContentChunksByText(n,o,s=10){if(n.length===0)return[];let{rows:i}=await e.query(`SELECT *, ts_rank(tsv, plainto_tsquery('english', $2)) AS score
|
|
57
|
+
FROM content_chunks
|
|
58
|
+
WHERE source_id = ANY($1) AND tsv @@ plainto_tsquery('english', $2)
|
|
59
|
+
ORDER BY score DESC
|
|
60
|
+
LIMIT $3`,[n,o,s]);return i.map(a=>({chunk:xt(a),score:a.score}))},async deleteContentChunksBySource(n){let{rowCount:o}=await e.query("DELETE FROM content_chunks WHERE source_id = $1",[n]);return o??0},async saveCredential(n){let{rows:o}=await e.query(`INSERT INTO encrypted_credentials (user_id, provider, encrypted_data, iv, auth_tag)
|
|
61
|
+
VALUES ($1, $2, $3, $4, $5)
|
|
62
|
+
ON CONFLICT (user_id, provider) DO UPDATE
|
|
63
|
+
SET encrypted_data = $3, iv = $4, auth_tag = $5, updated_at = now()
|
|
64
|
+
RETURNING *`,[n.userId,n.provider,n.encryptedData,n.iv,n.authTag]);return wt(o[0])},async getCredential(n,o){let{rows:s}=await e.query("SELECT * FROM encrypted_credentials WHERE user_id = $1 AND provider = $2",[n,o]);return s[0]?wt(s[0]):null},async deleteCredential(n){await e.query("DELETE FROM encrypted_credentials WHERE id = $1",[n])},async listCredentials(n){let{rows:o}=await e.query("SELECT * FROM encrypted_credentials WHERE user_id = $1 ORDER BY provider",[n]);return o.map(wt)},async saveIdentityFile(n){let{rows:o}=await e.query(`INSERT INTO identity_files (workspace_id, file_name, content, metadata)
|
|
65
|
+
VALUES ($1, $2, $3, $4)
|
|
66
|
+
ON CONFLICT (workspace_id, file_name) DO UPDATE
|
|
67
|
+
SET content = $3, metadata = $4, updated_at = now()
|
|
68
|
+
RETURNING *`,[n.workspaceId,n.fileName,n.content,JSON.stringify(n.metadata)]);return Ct(o[0])},async getIdentityFile(n){let{rows:o}=await e.query("SELECT * FROM identity_files WHERE workspace_id = $1 ORDER BY created_at DESC LIMIT 1",[n]);return o[0]?Ct(o[0]):null},async listIdentityFiles(){let{rows:n}=await e.query("SELECT * FROM identity_files ORDER BY created_at DESC");return n.map(Ct)},async query(n,o){let{rows:s}=await e.query(n,o);return s}}}var ko,So,Re=ve(()=>{"use strict";({Pool:ko}=Eo),So=`
|
|
69
|
+
-- \u2550\u2550\u2550 Extensions \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
70
|
+
CREATE EXTENSION IF NOT EXISTS vector;
|
|
71
|
+
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
72
|
+
|
|
73
|
+
-- \u2550\u2550\u2550 v1.2 \u2014 Core tables \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
74
|
+
|
|
75
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
76
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
77
|
+
external_id TEXT NOT NULL,
|
|
78
|
+
platform TEXT NOT NULL,
|
|
79
|
+
display_name TEXT,
|
|
80
|
+
email TEXT,
|
|
81
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
82
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
83
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
84
|
+
UNIQUE (external_id, platform)
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
CREATE TABLE IF NOT EXISTS conversations (
|
|
88
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
89
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
90
|
+
title TEXT,
|
|
91
|
+
channel TEXT NOT NULL DEFAULT 'web',
|
|
92
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
93
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
94
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
95
|
+
);
|
|
96
|
+
CREATE INDEX IF NOT EXISTS idx_conversations_user ON conversations(user_id, updated_at DESC);
|
|
97
|
+
|
|
98
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
99
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
100
|
+
conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
|
|
101
|
+
user_id TEXT NOT NULL,
|
|
102
|
+
role TEXT NOT NULL,
|
|
103
|
+
content TEXT NOT NULL,
|
|
104
|
+
channel TEXT NOT NULL DEFAULT 'web',
|
|
105
|
+
token_count INTEGER,
|
|
106
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
107
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
108
|
+
);
|
|
109
|
+
CREATE INDEX IF NOT EXISTS idx_messages_conversation ON messages(conversation_id, created_at);
|
|
110
|
+
CREATE INDEX IF NOT EXISTS idx_messages_user ON messages(user_id, created_at DESC);
|
|
111
|
+
|
|
112
|
+
CREATE TABLE IF NOT EXISTS memory_segments (
|
|
113
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
114
|
+
user_id TEXT NOT NULL,
|
|
115
|
+
content TEXT NOT NULL,
|
|
116
|
+
category TEXT NOT NULL DEFAULT 'fact',
|
|
117
|
+
embedding vector(1536),
|
|
118
|
+
heat REAL NOT NULL DEFAULT 1.0,
|
|
119
|
+
access_count INTEGER NOT NULL DEFAULT 0,
|
|
120
|
+
last_accessed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
121
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
122
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
123
|
+
);
|
|
124
|
+
CREATE INDEX IF NOT EXISTS idx_memory_user ON memory_segments(user_id);
|
|
125
|
+
CREATE INDEX IF NOT EXISTS idx_memory_updated ON memory_segments(updated_at DESC);
|
|
126
|
+
|
|
127
|
+
-- ivfflat index for vector search (created only if enough rows exist or deferred)
|
|
128
|
+
-- We use a DO block so it doesn't fail on first run with zero rows.
|
|
129
|
+
DO $$
|
|
130
|
+
BEGIN
|
|
131
|
+
IF NOT EXISTS (
|
|
132
|
+
SELECT 1 FROM pg_indexes WHERE indexname = 'idx_memory_embedding_ivfflat'
|
|
133
|
+
) THEN
|
|
134
|
+
BEGIN
|
|
135
|
+
CREATE INDEX idx_memory_embedding_ivfflat
|
|
136
|
+
ON memory_segments USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
|
|
137
|
+
EXCEPTION WHEN others THEN
|
|
138
|
+
-- ivfflat requires rows to train; will be created later
|
|
139
|
+
RAISE NOTICE 'Skipping ivfflat index (likely not enough rows): %', SQLERRM;
|
|
140
|
+
END;
|
|
141
|
+
END IF;
|
|
142
|
+
END $$;
|
|
143
|
+
|
|
144
|
+
CREATE TABLE IF NOT EXISTS user_profiles (
|
|
145
|
+
user_id TEXT PRIMARY KEY,
|
|
146
|
+
summary TEXT NOT NULL,
|
|
147
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
CREATE TABLE IF NOT EXISTS observations (
|
|
151
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
152
|
+
user_id TEXT NOT NULL,
|
|
153
|
+
conversation_id TEXT,
|
|
154
|
+
content TEXT NOT NULL,
|
|
155
|
+
category TEXT NOT NULL DEFAULT 'general',
|
|
156
|
+
reviewed BOOLEAN NOT NULL DEFAULT FALSE,
|
|
157
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
158
|
+
reviewed_at TIMESTAMPTZ
|
|
159
|
+
);
|
|
160
|
+
CREATE INDEX IF NOT EXISTS idx_observations_pending ON observations(user_id) WHERE NOT reviewed;
|
|
161
|
+
|
|
162
|
+
-- \u2550\u2550\u2550 v1.4 \u2014 Knowledge graph + cost + artifacts \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
163
|
+
|
|
164
|
+
CREATE TABLE IF NOT EXISTS entities (
|
|
165
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
166
|
+
user_id TEXT NOT NULL,
|
|
167
|
+
name TEXT NOT NULL,
|
|
168
|
+
entity_type TEXT NOT NULL,
|
|
169
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
170
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
171
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
172
|
+
);
|
|
173
|
+
CREATE INDEX IF NOT EXISTS idx_entities_user ON entities(user_id);
|
|
174
|
+
|
|
175
|
+
CREATE TABLE IF NOT EXISTS relations (
|
|
176
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
177
|
+
user_id TEXT NOT NULL,
|
|
178
|
+
source_entity_id TEXT NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
179
|
+
target_entity_id TEXT NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
180
|
+
relation_type TEXT NOT NULL,
|
|
181
|
+
strength REAL NOT NULL DEFAULT 1.0,
|
|
182
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
183
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
184
|
+
);
|
|
185
|
+
CREATE INDEX IF NOT EXISTS idx_relations_source ON relations(source_entity_id);
|
|
186
|
+
CREATE INDEX IF NOT EXISTS idx_relations_target ON relations(target_entity_id);
|
|
187
|
+
|
|
188
|
+
CREATE TABLE IF NOT EXISTS checkpoints (
|
|
189
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
190
|
+
conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
|
|
191
|
+
summary TEXT NOT NULL,
|
|
192
|
+
tokens_saved INTEGER NOT NULL DEFAULT 0,
|
|
193
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
194
|
+
);
|
|
195
|
+
CREATE INDEX IF NOT EXISTS idx_checkpoints_conv ON checkpoints(conversation_id, created_at DESC);
|
|
196
|
+
|
|
197
|
+
CREATE TABLE IF NOT EXISTS cost_logs (
|
|
198
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
199
|
+
user_id TEXT NOT NULL,
|
|
200
|
+
conversation_id TEXT,
|
|
201
|
+
provider TEXT NOT NULL,
|
|
202
|
+
model TEXT NOT NULL,
|
|
203
|
+
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
204
|
+
output_tokens INTEGER NOT NULL DEFAULT 0,
|
|
205
|
+
cost_usd REAL NOT NULL DEFAULT 0,
|
|
206
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
207
|
+
);
|
|
208
|
+
CREATE INDEX IF NOT EXISTS idx_cost_logs_user_date ON cost_logs(user_id, created_at);
|
|
209
|
+
|
|
210
|
+
CREATE TABLE IF NOT EXISTS brain_artifacts (
|
|
211
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
212
|
+
conversation_id TEXT NOT NULL,
|
|
213
|
+
artifact_type TEXT NOT NULL,
|
|
214
|
+
title TEXT NOT NULL,
|
|
215
|
+
content TEXT NOT NULL,
|
|
216
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
217
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
218
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
219
|
+
);
|
|
220
|
+
CREATE INDEX IF NOT EXISTS idx_brain_artifacts_conv ON brain_artifacts(conversation_id);
|
|
221
|
+
|
|
222
|
+
CREATE TABLE IF NOT EXISTS approval_records (
|
|
223
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
224
|
+
user_id TEXT NOT NULL,
|
|
225
|
+
conversation_id TEXT NOT NULL,
|
|
226
|
+
action TEXT NOT NULL,
|
|
227
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
228
|
+
payload JSONB NOT NULL DEFAULT '{}',
|
|
229
|
+
decided_at TIMESTAMPTZ,
|
|
230
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
231
|
+
);
|
|
232
|
+
CREATE INDEX IF NOT EXISTS idx_approvals_user ON approval_records(user_id, created_at DESC);
|
|
233
|
+
|
|
234
|
+
-- \u2550\u2550\u2550 v1.5 \u2014 Jobs, content pipeline, credentials \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
235
|
+
|
|
236
|
+
CREATE TABLE IF NOT EXISTS jobs (
|
|
237
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
238
|
+
type TEXT NOT NULL,
|
|
239
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
240
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
241
|
+
payload JSONB NOT NULL DEFAULT '{}',
|
|
242
|
+
result JSONB,
|
|
243
|
+
error TEXT,
|
|
244
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
245
|
+
max_attempts INTEGER NOT NULL DEFAULT 3,
|
|
246
|
+
claimed_at TIMESTAMPTZ,
|
|
247
|
+
completed_at TIMESTAMPTZ,
|
|
248
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
249
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
250
|
+
);
|
|
251
|
+
-- Priority-ordered index for SKIP LOCKED claiming
|
|
252
|
+
CREATE INDEX IF NOT EXISTS idx_jobs_claimable
|
|
253
|
+
ON jobs(priority DESC, created_at ASC)
|
|
254
|
+
WHERE status = 'pending';
|
|
255
|
+
CREATE INDEX IF NOT EXISTS idx_jobs_status ON jobs(status);
|
|
256
|
+
CREATE INDEX IF NOT EXISTS idx_jobs_type ON jobs(type);
|
|
257
|
+
|
|
258
|
+
CREATE TABLE IF NOT EXISTS content_sources (
|
|
259
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
260
|
+
user_id TEXT NOT NULL,
|
|
261
|
+
source_type TEXT NOT NULL,
|
|
262
|
+
uri TEXT NOT NULL,
|
|
263
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
264
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
265
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
266
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
267
|
+
);
|
|
268
|
+
CREATE INDEX IF NOT EXISTS idx_content_sources_user ON content_sources(user_id);
|
|
269
|
+
|
|
270
|
+
CREATE TABLE IF NOT EXISTS content_chunks (
|
|
271
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
272
|
+
source_id TEXT NOT NULL REFERENCES content_sources(id) ON DELETE CASCADE,
|
|
273
|
+
content TEXT NOT NULL,
|
|
274
|
+
embedding vector(1536),
|
|
275
|
+
chunk_index INTEGER NOT NULL DEFAULT 0,
|
|
276
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
277
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
278
|
+
);
|
|
279
|
+
CREATE INDEX IF NOT EXISTS idx_content_chunks_source ON content_chunks(source_id);
|
|
280
|
+
|
|
281
|
+
-- Full-text GIN index on content_chunks
|
|
282
|
+
DO $$
|
|
283
|
+
BEGIN
|
|
284
|
+
IF NOT EXISTS (
|
|
285
|
+
SELECT 1 FROM information_schema.columns
|
|
286
|
+
WHERE table_name = 'content_chunks' AND column_name = 'tsv'
|
|
287
|
+
) THEN
|
|
288
|
+
ALTER TABLE content_chunks ADD COLUMN tsv tsvector
|
|
289
|
+
GENERATED ALWAYS AS (to_tsvector('english', content)) STORED;
|
|
290
|
+
CREATE INDEX idx_content_chunks_tsv ON content_chunks USING GIN(tsv);
|
|
291
|
+
END IF;
|
|
292
|
+
END $$;
|
|
293
|
+
|
|
294
|
+
-- pgvector index on content_chunks
|
|
295
|
+
DO $$
|
|
296
|
+
BEGIN
|
|
297
|
+
IF NOT EXISTS (
|
|
298
|
+
SELECT 1 FROM pg_indexes WHERE indexname = 'idx_content_chunks_embedding'
|
|
299
|
+
) THEN
|
|
300
|
+
BEGIN
|
|
301
|
+
CREATE INDEX idx_content_chunks_embedding
|
|
302
|
+
ON content_chunks USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
|
|
303
|
+
EXCEPTION WHEN others THEN
|
|
304
|
+
RAISE NOTICE 'Skipping content_chunks ivfflat index: %', SQLERRM;
|
|
305
|
+
END;
|
|
306
|
+
END IF;
|
|
307
|
+
END $$;
|
|
308
|
+
|
|
309
|
+
-- AES-256-GCM encrypted credentials
|
|
310
|
+
CREATE TABLE IF NOT EXISTS encrypted_credentials (
|
|
311
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
312
|
+
user_id TEXT NOT NULL,
|
|
313
|
+
provider TEXT NOT NULL,
|
|
314
|
+
encrypted_data BYTEA NOT NULL,
|
|
315
|
+
iv BYTEA NOT NULL,
|
|
316
|
+
auth_tag BYTEA NOT NULL,
|
|
317
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
318
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
319
|
+
UNIQUE (user_id, provider)
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
-- \u2550\u2550\u2550 v1.6 \u2014 Identity files, cost events \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
323
|
+
|
|
324
|
+
CREATE TABLE IF NOT EXISTS identity_files (
|
|
325
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
326
|
+
workspace_id TEXT NOT NULL,
|
|
327
|
+
file_name TEXT NOT NULL,
|
|
328
|
+
content TEXT NOT NULL,
|
|
329
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
330
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
331
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
332
|
+
UNIQUE (workspace_id, file_name)
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
CREATE TABLE IF NOT EXISTS cost_events (
|
|
336
|
+
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
337
|
+
user_id TEXT NOT NULL,
|
|
338
|
+
event_type TEXT NOT NULL,
|
|
339
|
+
amount REAL NOT NULL DEFAULT 0,
|
|
340
|
+
currency TEXT NOT NULL DEFAULT 'USD',
|
|
341
|
+
metadata JSONB NOT NULL DEFAULT '{}',
|
|
342
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
343
|
+
);
|
|
344
|
+
CREATE INDEX IF NOT EXISTS idx_cost_events_user ON cost_events(user_id, created_at);
|
|
345
|
+
`});function h(){throw new Error(xo)}function pe(){return{initialize:h,close:h,saveMessage:h,getMessagesByConversation:h,getMessageById:h,createConversation:h,listConversations:h,deleteConversation:h,saveMemorySegment:h,searchMemoryByEmbedding:h,getProfile:h,upsertProfile:h,updateHeatScores:h,saveObservation:h,listPendingObservations:h,markObservationReviewed:h,saveBrainArtifact:h,loadBrainArtifacts:h,deleteBrainArtifact:h,insertCostLog:h,queryCostLogs:h,createJob:h,claimNextJob:h,updateJobStatus:h,getJobById:h,listJobs:h,markDeadJobs:h,createContentSource:h,updateContentSourceStatus:h,getContentSourceById:h,listContentSources:h,bulkInsertContentChunks:h,searchContentChunksByEmbedding:h,searchContentChunksByText:h,deleteContentChunksBySource:h,saveCredential:h,getCredential:h,deleteCredential:h,listCredentials:h,saveIdentityFile:h,getIdentityFile:h,listIdentityFiles:h,query:h}}var xo,Ie=ve(()=>{"use strict";xo="SQLite not implemented \u2014 use PostgreSQL. Mobile edition will use SQLite + zvec."});var On=ve(()=>{"use strict"});var $n={};cr($n,{createPostgresStorage:()=>ue,createSqliteStorage:()=>pe,createStorage:()=>Dn});function Dn(t){switch(t.backend){case"postgres":{if(!t.connectionString)throw new Error("connectionString is required for the postgres backend");return ue({connectionString:t.connectionString,max:t.maxConnections})}case"sqlite":return pe();default:throw new Error(`Unknown storage backend: ${t.backend}`)}}var At=ve(()=>{"use strict";Re();Ie();On();Re();Ie()});var Be={name:"mobile",label:"Fenix Mobile",tools:[],categories:["llm","file","memory","notification"],maxWorkers:1};var wr={failureThreshold:5,resetTimeoutMs:6e4,maxResetTimeoutMs:36e5,billingResetTimeoutMs:18e6,billingMaxResetTimeoutMs:864e5};function Cr(t){if(typeof t=="object"&&t!==null){let e=t.statusCode??t.status;if(e===402||e===429)return!0;let r=t.message??"";return/quota|billing|rate.limit|insufficient.funds|payment.required/i.test(r)}return!1}var te=class t{state="closed";failureCount=0;consecutiveResets=0;lastFailureTime=0;isBillingFailure=!1;config;keyBreakers=null;constructor(e){this.config={...wr,...e}}getState(){return this.state==="open"&&Date.now()-this.lastFailureTime>=this.currentTimeout()&&(this.state="half-open"),this.state}canAttempt(){let e=this.getState();return e==="closed"||e==="half-open"}recordSuccess(){this.failureCount=0,this.consecutiveResets=0,this.isBillingFailure=!1,this.state="closed"}recordFailure(e){this.failureCount++,this.lastFailureTime=Date.now(),this.isBillingFailure=Cr(e),(this.state==="half-open"||this.failureCount>=this.config.failureThreshold)&&(this.state==="half-open"&&this.consecutiveResets++,this.state="open")}getKeyBreaker(e){this.keyBreakers||(this.keyBreakers=new Map);let r=this.keyBreakers.get(e);return r||(r=new t(this.config),this.keyBreakers.set(e,r)),r}getHealthyKey(e){if(!this.keyBreakers)return e[0]??null;for(let r of e){let n=this.keyBreakers.get(r);if(!n||n.canAttempt())return r}return null}currentTimeout(){return this.isBillingFailure?Math.min(this.config.billingResetTimeoutMs*2**this.consecutiveResets,this.config.billingMaxResetTimeoutMs):Math.min(this.config.resetTimeoutMs*2**this.consecutiveResets,this.config.maxResetTimeoutMs)}};function ln(t){return t.priority??5}function Ar(t){return t.urgency??"immediate"}function dn(t,e){return e.priority-t.priority}var Q=class{handlers=new Map;allHandlers=new Set;errorHandler;soonQueue=[];soonScheduled=!1;laterQueue=[];subscribe(e,r){return this.handlers.has(e)||this.handlers.set(e,new Set),this.handlers.get(e).add(r),()=>{this.handlers.get(e)?.delete(r)}}subscribeAll(e){return this.allHandlers.add(e),()=>{this.allHandlers.delete(e)}}onError(e){this.errorHandler=e}async emit(e){let r=Ar(e);if(r==="soon"){this.soonQueue.push({event:e,priority:ln(e)}),this.scheduleSoonDrain();return}if(r==="later"){this.laterQueue.push({event:e,priority:ln(e)});return}await this.deliver(e)}async drainDeferred(){if(this.laterQueue.length===0)return 0;let e=this.laterQueue.splice(0);e.sort(dn);for(let{event:r}of e)await this.deliver(r);return e.length}get pendingCount(){return this.soonQueue.length+this.laterQueue.length}listenerCount(e){if(e)return(this.handlers.get(e)?.size??0)+this.allHandlers.size;let r=this.allHandlers.size;for(let n of this.handlers.values())r+=n.size;return r}clear(){this.handlers.clear(),this.allHandlers.clear(),this.soonQueue.length=0,this.laterQueue.length=0}async deliver(e){let r=[],n=this.handlers.get(e.type);if(n&&r.push(...n),r.push(...this.allHandlers),r.length===0)return;let o=await Promise.allSettled(r.map(async s=>s(e)));for(let s of o)s.status==="rejected"&&this.errorHandler&&this.errorHandler(s.reason,e)}scheduleSoonDrain(){this.soonScheduled||(this.soonScheduled=!0,queueMicrotask(async()=>{this.soonScheduled=!1;let e=this.soonQueue.splice(0);e.sort(dn);for(let{event:r}of e)await this.deliver(r)}))}};var Y=class{sessions=new Map;timers=new Map;bufferTtlMs;maxBufferSize;constructor(e){this.bufferTtlMs=e?.bufferTtlMs??1800*1e3,this.maxBufferSize=e?.maxBufferSize??1e4}create(e){let r=e??`sess-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,n={id:r,createdAt:Date.now(),events:[],listeners:new Set};return this.sessions.set(r,n),this.resetTtl(r),n}get(e){return this.sessions.get(e)}subscribe(e,r){let n=this.sessions.get(e);if(!n)throw new Error(`Session not found: ${e}`);return n.listeners.add(r),()=>{n.listeners.delete(r)}}async bufferEvent(e,r){let n=this.sessions.get(e);if(n){n.events.length>=this.maxBufferSize&&n.events.shift(),n.events.push(r),this.resetTtl(e);for(let o of n.listeners)o(r)}}replay(e,r){let n=this.sessions.get(e);if(!n)return 0;for(let o of n.events)r(o);return n.events.length}connectBus(e,r){return e.subscribeAll(n=>{"sessionId"in n&&n.sessionId===r&&this.bufferEvent(r,n)})}delete(e){return this.clearTtl(e),this.sessions.delete(e)}get size(){return this.sessions.size}destroy(){for(let[e]of this.sessions)this.clearTtl(e);this.sessions.clear()}resetTtl(e){this.clearTtl(e),this.timers.set(e,setTimeout(()=>{this.sessions.delete(e),this.timers.delete(e)},this.bufferTtlMs))}clearTtl(e){let r=this.timers.get(e);r&&(clearTimeout(r),this.timers.delete(e))}};var Te=class{constructor(e,r=3,n=15){this.inner=e;this.inputCostPerM=r;this.outputCostPerM=n;this.id=e.id,e.stream&&(this.stream=o=>{this.model=o.model??this.model;let s=e.stream(o);return this.wrapStream(s)}),e.generateObject&&(this.generateObject=async o=>{this.model=o.model??this.model;let s=await e.generateObject(o),i=o.messages.reduce((c,l)=>c+(typeof l.content=="string"?l.content.length:0),0),a=JSON.stringify(s).length;return this.record(Math.ceil(i/4),Math.ceil(a/4)),s}),e.streamObject&&(this.streamObject=o=>{this.model=o.model??this.model;let s=e.streamObject(o);return this.wrapObjectStream(s)})}id;records=[];model="unknown";stream;generateObject;streamObject;capabilities(){return this.inner.capabilities()}async complete(e){this.model=e.model??this.model;let r=await this.inner.complete(e);return r.usage&&this.record(r.usage.inputTokens,r.usage.outputTokens),r}async embed(e){if(!this.inner.embed)throw new Error(`Provider ${this.id} does not support embeddings`);let r=await this.inner.embed(e);return r.usage&&this.record(r.usage.totalTokens,0),r}getRecords(){return this.records}getSummary(){let e=0,r=0,n=0;for(let o of this.records)e+=o.inputTokens,r+=o.outputTokens,n+=o.estimatedCost;return{totalInputTokens:e,totalOutputTokens:r,totalEstimatedCost:n,recordCount:this.records.length}}record(e,r){let n=e/1e6*this.inputCostPerM+r/1e6*this.outputCostPerM;this.records.push({provider:this.id,model:this.model,inputTokens:e,outputTokens:r,estimatedCost:n,timestamp:Date.now()})}wrapStream(e){let r=this;return{[Symbol.asyncIterator](){let n=e[Symbol.asyncIterator]();return{async next(){let o=await n.next();return!o.done&&o.value.usage&&r.record(o.value.usage.prompt_tokens??0,o.value.usage.completion_tokens??0),o}}}}}wrapObjectStream(e){let r=this;return{[Symbol.asyncIterator](){let n=e[Symbol.asyncIterator]();return{async next(){let o=await n.next();return!o.done&&o.value.usage&&r.record(o.value.usage.inputTokens,o.value.usage.outputTokens),o}}}}}};var un=[{id:"anthropic",envVars:["ANTHROPIC_API_KEY"]},{id:"openai",envVars:["OPENAI_API_KEY"]},{id:"google",envVars:["GOOGLE_API_KEY"]},{id:"openrouter",envVars:["OPENROUTER_API_KEY"]},{id:"groq",envVars:["GROQ_API_KEY"]},{id:"bedrock",envVars:["AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY"]},{id:"nvidia",envVars:["NVIDIA_API_KEY"]},{id:"cloudflare",envVars:["CLOUDFLARE_API_TOKEN"]},{id:"github",envVars:["GITHUB_TOKEN"]}],pn="http://localhost:11434",Rr=[{id:"sidecar-qwen3",type:"gpu-model",modelPath:"Qwen3-TTS"},{id:"google-tts",type:"env",envVars:["GOOGLE_API_KEY"]},{id:"sidecar-moss",type:"gpu-model",modelPath:"MOSS-TTS"},{id:"speechmatics-tts",type:"env",envVars:["SPEECHMATICS_API_KEY"]},{id:"elevenlabs",type:"env",envVars:["ELEVENLABS_API_KEY"]},{id:"deepgram-tts",type:"env",envVars:["DEEPGRAM_API_KEY"]},{id:"openai-tts",type:"env",envVars:["OPENAI_API_KEY"]},{id:"groq",type:"env",envVars:["GROQ_API_KEY"]},{id:"nvidia",type:"env",envVars:["NVIDIA_API_KEY"]},{id:"cloudflare",type:"env",envVars:["CLOUDFLARE_API_TOKEN"]}],Ir=[{id:"sidecar-parakeet",type:"gpu-model",modelPath:"Parakeet"},{id:"groq",type:"env",envVars:["GROQ_API_KEY"]},{id:"speechmatics",type:"env",envVars:["SPEECHMATICS_API_KEY"]},{id:"deepgram",type:"env",envVars:["DEEPGRAM_API_KEY"]},{id:"google-stt",type:"env",envVars:["GOOGLE_API_KEY"]},{id:"sidecar-whisper",type:"gpu-model",modelPath:"Whisper"},{id:"nvidia",type:"env",envVars:["NVIDIA_API_KEY"]}];function je(t){return t.every(e=>!!process.env[e])}function _r(){return!!(process.env.CUDA_VISIBLE_DEVICES||process.env.NVIDIA_VISIBLE_DEVICES)}async function Pr(t){try{let e=new AbortController,r=setTimeout(()=>e.abort(),2e3),n=await fetch(`${t}/api/tags`,{signal:e.signal});return clearTimeout(r),n.ok}catch{return!1}}async function ne(){let t=[],e=null;for(let s of un)if(je(s.envVars)){e={id:s.id,slot:"chat",apiKeyEnv:s.envVars[0]};break}if(!e&&await Pr(pn)&&(e={id:"ollama",slot:"chat",baseUrl:pn}),!e){let s=un.map(i=>i.envVars.join(" + ")).join(", ");throw new Error(`No LLM provider detected. Set one of: ${s}, or run Ollama on localhost:11434`)}let r=null,n=_r();for(let s of Rr){if(s.type==="gpu-model"&&n){r={id:s.id,slot:"tts"};break}if(s.type==="env"&&s.envVars&&je(s.envVars)){r={id:s.id,slot:"tts",apiKeyEnv:s.envVars[0]},e.apiKeyEnv&&e.apiKeyEnv===s.envVars[0]&&t.push(e.apiKeyEnv);break}}let o=null;for(let s of Ir){if(s.type==="gpu-model"&&n){o={id:s.id,slot:"stt"};break}if(s.type==="env"&&s.envVars&&je(s.envVars)){o={id:s.id,slot:"stt",apiKeyEnv:s.envVars[0]},e.apiKeyEnv&&e.apiKeyEnv===s.envVars[0]&&!t.includes(e.apiKeyEnv)&&t.push(e.apiKeyEnv);break}}return{chat:e,tts:r,stt:o,reusedKeys:t}}var q=class{slots=new Map;enableCostTracking;constructor(e={}){this.enableCostTracking=e.enableCostTracking??!1}register(e,r){let n=this.enableCostTracking?new Te(r):r,o=new te;this.slots.set(e,{provider:n,breaker:o,slot:e})}getHealthy(e){let r=this.slots.get(e);return!r||!r.breaker.canAttempt()?null:r.provider}getBreaker(e){return this.slots.get(e)?.breaker??null}getByCapability(e,r="chat"){let n=[r];e==="vision"?(r!=="vision"&&n.unshift("vision"),n.includes("chat")||n.push("chat")):(n.includes("chat")||n.push("chat"),n.includes("utility")||n.push("utility"));for(let o of n){let s=this.slots.get(o);if(!s||!s.breaker.canAttempt())continue;if(s.provider.capabilities()[e])return s.provider}return null}listSlots(){return Array.from(this.slots.keys())}get(e){return this.slots.get(e)}hasSlots(){return this.slots.size>0}static async autoDetect(){return ne()}};function be(t){try{return JSON.parse(t)}catch{}let e=t.trim();e.startsWith("```json")?e=e.slice(7):e.startsWith("```")&&(e=e.slice(3)),e.endsWith("```")&&(e=e.slice(0,-3)),e=e.trim();try{return JSON.parse(e)}catch{}e=e.replace(/,\s*([\]}])/g,"$1");try{return JSON.parse(e)}catch{}e=mn(e);try{return JSON.parse(e)}catch{let r=Mr(e);if(r!==e)try{return JSON.parse(r)}catch{}}throw new Error(`Unable to repair JSON: ${t.slice(0,100)}...`)}function z(t){if(t.trim())try{return be(t)}catch{return}}function mn(t){let e=!1,r=!1,n=[];for(let o=0;o<t.length;o++){let s=t[o];if(r){r=!1;continue}if(s==="\\"){r=!0;continue}if(s==='"'){e=!e;continue}e||(s==="{"?n.push("}"):s==="["?n.push("]"):(s==="}"||s==="]")&&n.length>0&&n[n.length-1]===s&&n.pop())}for(e&&(t+='"'),t=t.replace(/,\s*$/,"");n.length>0;)t+=n.pop();return t}function Mr(t){let e=t.lastIndexOf(",");if(e>0){let r=t.slice(0,e);return mn(r)}return t}var L=class{id;baseUrl;apiKey;model;caps;constructor(e){this.id=e.id??`openai-compat:${e.model}`,this.baseUrl=e.baseUrl.replace(/\/+$/,""),this.apiKey=e.apiKey,this.model=e.model,this.caps={nativeToolCalling:!0,vision:!1,streaming:!0,structuredOutput:!0,maxContextTokens:128e3,...e.capabilities}}capabilities(){return{...this.caps}}async complete(e){let r=this.buildRequestBody(e,!1),n=await fetch(`${this.baseUrl}/v1/chat/completions`,{method:"POST",headers:this.headers(),body:JSON.stringify(r)});if(!n.ok){let a=await n.text().catch(()=>"");throw Object.assign(new Error(`OpenAI API error ${n.status}: ${a}`),{statusCode:n.status})}let o=await n.json(),s=o.choices[0],i=s?.message?.tool_calls?.map(a=>({id:a.id,type:"function",function:{name:a.function.name,arguments:a.function.arguments}}));return{content:s?.message?.content??"",toolCalls:i?.length?i:void 0,finishReason:this.mapFinishReason(s?.finish_reason),usage:o.usage?{inputTokens:o.usage.prompt_tokens,outputTokens:o.usage.completion_tokens}:void 0}}stream(e){let r=this,n=this.buildRequestBody(e,!0);return{[Symbol.asyncIterator](){let o=null,s="",i=!1;return{async next(){if(i)return{done:!0,value:void 0};if(!o){let c=await fetch(`${r.baseUrl}/v1/chat/completions`,{method:"POST",headers:r.headers(),body:JSON.stringify(n)});if(!c.ok){let l=await c.text().catch(()=>"");throw Object.assign(new Error(`OpenAI API error ${c.status}: ${l}`),{statusCode:c.status})}o=c.body.getReader()}let a=new TextDecoder;for(;;){let c=s.indexOf(`
|
|
346
|
+
`);if(c!==-1){let u=s.slice(0,c).trim();if(s=s.slice(c+1),u==="data: [DONE]")return i=!0,{done:!0,value:void 0};if(u.startsWith("data: "))try{return{done:!1,value:JSON.parse(u.slice(6))}}catch{continue}continue}let{value:l,done:d}=await o.read();if(d)return i=!0,{done:!0,value:void 0};s+=a.decode(l,{stream:!0})}}}}}}async embed(e){let r=Array.isArray(e)?e:[e],n=await fetch(`${this.baseUrl}/v1/embeddings`,{method:"POST",headers:this.headers(),body:JSON.stringify({model:this.model,input:r})});if(!n.ok){let s=await n.text().catch(()=>"");throw Object.assign(new Error(`OpenAI Embeddings API error ${n.status}: ${s}`),{statusCode:n.status})}let o=await n.json();return{embeddings:o.data.map(s=>s.embedding),usage:o.usage?{totalTokens:o.usage.total_tokens}:void 0}}async generateObject(e){let r={model:e.model??this.model,messages:e.messages,response_format:{type:"json_schema",json_schema:{name:e.schemaName??"response",description:e.schemaDescription,schema:e.schema,strict:!0}}};e.temperature!==void 0&&(r.temperature=e.temperature),e.maxTokens!==void 0&&(r.max_tokens=e.maxTokens);let n=await fetch(`${this.baseUrl}/v1/chat/completions`,{method:"POST",headers:this.headers(),body:JSON.stringify(r)});if(!n.ok){let i=await n.text().catch(()=>"");throw Object.assign(new Error(`OpenAI API error ${n.status}: ${i}`),{statusCode:n.status})}let s=(await n.json()).choices[0]?.message?.content??"";return be(s)}streamObject(e){let r=this,n={model:e.model??this.model,messages:e.messages,stream:!0,stream_options:{include_usage:!0},response_format:{type:"json_schema",json_schema:{name:e.schemaName??"response",description:e.schemaDescription,schema:e.schema,strict:!0}}};return e.temperature!==void 0&&(n.temperature=e.temperature),e.maxTokens!==void 0&&(n.max_tokens=e.maxTokens),{[Symbol.asyncIterator](){let o=null,s="",i="",a=!1;return{async next(){if(a)return{done:!0,value:void 0};if(!o){let l=await fetch(`${r.baseUrl}/v1/chat/completions`,{method:"POST",headers:r.headers(),body:JSON.stringify(n)});if(!l.ok){let d=await l.text().catch(()=>"");throw Object.assign(new Error(`OpenAI API error ${l.status}: ${d}`),{statusCode:l.status})}o=l.body.getReader()}let c=new TextDecoder;for(;;){let l=s.indexOf(`
|
|
347
|
+
`);if(l!==-1){let f=s.slice(0,l).trim();if(s=s.slice(l+1),f==="data: [DONE]")return a=!0,{done:!1,value:{partial:z(i)??{},done:!0}};if(f.startsWith("data: "))try{let T=JSON.parse(f.slice(6)),v=T.choices?.[0]?.delta?.content;if(v){i+=v;let g=z(i);if(g!==void 0){let p=T.usage?{inputTokens:T.usage.prompt_tokens??0,outputTokens:T.usage.completion_tokens??0}:void 0;return{done:!1,value:{partial:g,done:!1,usage:p}}}}if(T.usage&&!v)return{done:!1,value:{partial:z(i)??{},done:!1,usage:{inputTokens:T.usage.prompt_tokens??0,outputTokens:T.usage.completion_tokens??0}}}}catch{continue}continue}let{value:d,done:u}=await o.read();if(u)return a=!0,{done:!1,value:{partial:z(i)??{},done:!0}};s+=c.decode(d,{stream:!0})}}}}}}headers(){return{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`}}buildRequestBody(e,r){let n={model:e.model??this.model,messages:e.messages,stream:r};return e.temperature!==void 0&&(n.temperature=e.temperature),e.maxTokens!==void 0&&(n.max_tokens=e.maxTokens),e.tools?.length&&(n.tools=e.tools),e.stop!==void 0&&(n.stop=e.stop),r&&(n.stream_options={include_usage:!0}),n}mapFinishReason(e){switch(e){case"stop":return"stop";case"tool_calls":return"tool_calls";case"length":return"length";case"content_filter":return"content_filter";default:return null}}};var Nr="2023-06-01",re=class{id;apiKey;model;baseUrl;maxTokens;constructor(e){this.id=e.id??`anthropic:${e.model}`,this.apiKey=e.apiKey,this.model=e.model,this.baseUrl=(e.baseUrl??"https://api.anthropic.com").replace(/\/+$/,""),this.maxTokens=e.maxTokens??4096}capabilities(){return{nativeToolCalling:!0,vision:!0,streaming:!0,structuredOutput:!1,maxContextTokens:2e5}}async complete(e){let r=this.buildRequestBody(e),n=await fetch(`${this.baseUrl}/v1/messages`,{method:"POST",headers:this.headers(),body:JSON.stringify(r)});if(!n.ok){let a=await n.text().catch(()=>"");throw Object.assign(new Error(`Anthropic API error ${n.status}: ${a}`),{statusCode:n.status})}let o=await n.json(),s="",i=[];for(let a of o.content)a.type==="text"&&a.text?s+=a.text:a.type==="tool_use"&&a.id&&a.name&&i.push({id:a.id,type:"function",function:{name:a.name,arguments:JSON.stringify(a.input??{})}});return{content:s,toolCalls:i.length>0?i:void 0,finishReason:this.mapStopReason(o.stop_reason),usage:{inputTokens:o.usage.input_tokens,outputTokens:o.usage.output_tokens}}}stream(e){let r=this,n={...this.buildRequestBody(e),stream:!0};return{[Symbol.asyncIterator](){let o=null,s="",i=!1,a=0;return{async next(){if(i)return{done:!0,value:void 0};if(!o){let l=await fetch(`${r.baseUrl}/v1/messages`,{method:"POST",headers:r.headers(),body:JSON.stringify(n)});if(!l.ok){let d=await l.text().catch(()=>"");throw Object.assign(new Error(`Anthropic API error ${l.status}: ${d}`),{statusCode:l.status})}o=l.body.getReader()}let c=new TextDecoder;for(;;){let l=s.indexOf(`
|
|
348
|
+
`);if(l!==-1){let f=s.slice(0,l).trim();if(s=s.slice(l+1),!f.startsWith("data: "))continue;let T=f.slice(6),v;try{v=JSON.parse(T)}catch{continue}if(v.type==="message_start"&&v.message?.usage&&(a=v.message.usage.input_tokens),v.type==="content_block_delta"&&v.delta?.text)return{done:!1,value:{choices:[{delta:{content:v.delta.text},finish_reason:null,index:0}]}};if(v.type==="message_delta"){let g=v.usage?.output_tokens??0;return{done:!1,value:{choices:[{delta:{},finish_reason:v.delta?.stop_reason==="end_turn"?"stop":v.delta?.stop_reason??null,index:0}],usage:{prompt_tokens:a,completion_tokens:g}}}}if(v.type==="message_stop")return i=!0,{done:!0,value:void 0};continue}let{value:d,done:u}=await o.read();if(u)return i=!0,{done:!0,value:void 0};s+=c.decode(d,{stream:!0})}}}}}}headers(){return{"Content-Type":"application/json","x-api-key":this.apiKey,"anthropic-version":Nr}}buildRequestBody(e){let r,n=[];for(let s of e.messages)s.role==="system"?r=typeof s.content=="string"?s.content:"":n.push({role:s.role==="tool"?"user":s.role,content:this.convertContent(s)});let o={model:e.model??this.model,messages:n,max_tokens:e.maxTokens??this.maxTokens};return r&&(o.system=r),e.temperature!==void 0&&(o.temperature=e.temperature),e.stop!==void 0&&(o.stop_sequences=Array.isArray(e.stop)?e.stop:[e.stop]),e.tools?.length&&(o.tools=e.tools.map(s=>({name:s.function.name,description:s.function.description,input_schema:s.function.parameters??{type:"object",properties:{}}}))),o}convertContent(e){return typeof e.content=="string"?e.content:e.content===null?"":e.content.map(r=>r.type==="text"?{type:"text",text:r.text}:r.type==="image_url"&&r.image_url?{type:"image",source:{type:"url",url:r.image_url.url}}:{type:"text",text:""})}mapStopReason(e){switch(e){case"end_turn":case"stop_sequence":return"stop";case"tool_use":return"tool_calls";case"max_tokens":return"length";default:return null}}};async function He(t,e){let r=[...t].sort((o,s)=>o.priority-s.priority),n={...e.data};for(let o of r){if(!o.enabled||o.point==="event"&&e.event&&o.eventTypes?.length&&!o.eventTypes.includes(e.event.type))continue;let s={...e,data:n},i=await o.handler(s);if(i.data&&(n={...n,...i.data}),i.action==="skip"||i.action==="halt")return{action:i.action,data:n}}return{action:"continue",data:n}}var gn=0;function fn(t,e,r,n){return gn++,{id:n?.id??`hook-${gn}`,extensionId:t,point:e,priority:n?.priority??50,eventTypes:n?.eventTypes,handler:r,enabled:n?.enabled??!0}}var oe=class{extensions=new Map;hooks=new Map;allHooks=new Map;async register(e){this.extensions.has(e.id)&&await this.unregister(e.id),this.extensions.set(e.id,e);let r={extensionId:e.id,registerHook:(n,o,s)=>{let i=fn(e.id,n,o,s);this.allHooks.has(i.id)&&this.removeHook(i.id),this.allHooks.set(i.id,i);let a=this.hooks.get(n)??[];return a.push(i),this.hooks.set(n,a),i.id}};await e.setup(r)}async registerAll(e){for(let r of e)await this.register(r)}async unregister(e){let r=this.extensions.get(e);if(r){r.teardown&&await r.teardown();for(let[n,o]of this.hooks)this.hooks.set(n,o.filter(s=>s.extensionId!==e));for(let[n,o]of this.allHooks)o.extensionId===e&&this.allHooks.delete(n);this.extensions.delete(e)}}has(e){return this.extensions.has(e)}listExtensions(){return Array.from(this.extensions.keys())}getHooks(e){return[...this.hooks.get(e)??[]].sort((n,o)=>n.priority-o.priority)}getHook(e){return this.allHooks.get(e)}setHookEnabled(e,r){let n=this.allHooks.get(e);return n?(n.enabled=r,!0):!1}get hookCount(){return this.allHooks.size}async dispatch(e,r){let n=this.hooks.get(e)??[];return n.length===0?{action:"continue",data:r.data}:He(n,{...r,hookPoint:e})}async dispatchEvent(e,r,n){let o=this.hooks.get("event")??[];o.length!==0&&await He(o,{sessionId:r,hookPoint:"event",event:e,data:n??{}})}removeHook(e){let r=this.allHooks.get(e);if(!r)return;let n=this.hooks.get(r.point);n&&this.hooks.set(r.point,n.filter(o=>o.id!==e)),this.allHooks.delete(e)}};var W=class{tools=new Map;register(e){if(this.tools.has(e.name))throw new Error(`Tool "${e.name}" is already registered`);this.tools.set(e.name,e)}registerAll(e){for(let r of e)this.register(r)}get(e){return this.tools.get(e)}has(e){return this.tools.has(e)}list(e){let r=[];for(let n of this.tools.values())(!e||!n.modes?.length||n.modes.includes(e))&&r.push(n);return r}get size(){return this.tools.size}};var Ee=class{workspaceConfig={};editionConfig=null;canAccess(e,r){return e.requiredPermissions?.length?e.requiredPermissions.every(n=>r.permissions.includes(n)):!0}check(e,r){if(!e.requiredPermissions?.length)return null;let n=e.requiredPermissions.filter(o=>!r.permissions.includes(o));return n.length===0?null:{tool:e.name,reason:`Missing permissions: ${n.join(", ")}`,missing:n}}setWorkspaceConfig(e){this.workspaceConfig={...e}}getWorkspaceConfig(){return{...this.workspaceConfig}}setEditionConfig(e){this.editionConfig={...e}}getEditionConfig(){return this.editionConfig?{...this.editionConfig}:null}checkACL(e,r){let n=e.name;if(this.editionConfig&&!this.isToolInEdition(n))return{allowed:!1,tool:n,reason:`Tool "${n}" not available in active edition`};if(this.workspaceConfig.whitelist?.length&&!this.matchesPattern(n,this.workspaceConfig.whitelist))return{allowed:!1,tool:n,reason:`Tool "${n}" not in workspace whitelist`};if(this.workspaceConfig.blacklist?.length&&this.matchesPattern(n,this.workspaceConfig.blacklist))return{allowed:!1,tool:n,reason:`Tool "${n}" blocked by workspace blacklist`};let o=this.check(e,r);return o?{allowed:!1,tool:n,reason:o.reason}:{allowed:!0,tool:n,reason:"Access granted"}}filterVisible(e,r){return e.filter(n=>this.checkACL(n,r).allowed)}isToolInEdition(e){if(!this.editionConfig||this.editionConfig.tools.includes("*")||this.editionConfig.tools.includes(e))return!0;if(this.editionConfig.categories){for(let r of this.editionConfig.categories)if(e.startsWith(`${r}.`)||e===r)return!0}return!1}matchesPattern(e,r){for(let n of r)if(n==="*"||n===e||n.endsWith(".*")&&e.startsWith(`${n.slice(0,-2)}.`))return!0;return!1}};var J=class{constructor(e,r){this.registry=e;this.acl=r??new Ee}acl;async route(e,r){let n=this.registry.get(e.name);if(!n)return{name:e.name,error:`Unknown tool: "${e.name}"`};if(n.modes?.length&&!n.modes.includes(r.mode))return{name:e.name,error:`Tool "${e.name}" is not available in "${r.mode}" mode`};let o=this.acl.check(n,r);if(o)return{name:e.name,error:o.reason};try{let s=await n.handler(e.arguments,r);return{name:e.name,result:s}}catch(s){let i=s instanceof Error?s.message:String(s);return{name:e.name,error:i}}}listAvailable(e){return this.registry.list(e.mode).filter(r=>this.acl.canAccess(r,e))}};function Lr(t){return t.role!=="assistant"||!t.tool_calls?[]:t.tool_calls.map(e=>e.id)}function se(t){let e=Or(t);return Dr(t,e),Ur(t),Fr(t,e),Br(t,e),jr(t),Hr(t),t}function Or(t){let e=new Set;for(let r of t)for(let n of Lr(r))e.add(n);return e}function Dr(t,e){for(let r=t.length-1;r>=0;r--)t[r].role==="tool"&&t[r].tool_call_id&&!e.has(t[r].tool_call_id)&&t.splice(r,1)}function $r(t){return t.content===null?!t.tool_calls?.length:typeof t.content=="string"||Array.isArray(t.content)?t.content.length===0:!0}function Ur(t){for(let e=t.length-1;e>=0;e--)$r(t[e])&&t.splice(e,1)}function Fr(t,e){let r=[];for(let n=t.length-1;n>=0;n--)t[n].role==="tool"&&t[n].tool_call_id&&(r.push(t[n]),t.splice(n,1));r.reverse();for(let n of r){let o=n.tool_call_id,s=t.length;for(let i=0;i<t.length;i++){let a=t[i];if(a.role==="assistant"&&a.tool_calls&&a.tool_calls.some(c=>c.id===o)){for(s=i+1;s<t.length&&t[s].role==="tool";)s++;break}}t.splice(s,0,n)}}function Br(t,e){let r=new Set;for(let n of t)n.role==="tool"&&n.tool_call_id&&r.add(n.tool_call_id);for(let n of e)if(!r.has(n))for(let o=0;o<t.length;o++){let s=t[o];if(s.role==="assistant"&&s.tool_calls&&s.tool_calls.some(i=>i.id===n)){let i=o+1;for(;i<t.length&&t[i].role==="tool";)i++;t.splice(i,0,{role:"tool",content:"[session-repair] Tool result missing \u2014 session was interrupted.",tool_call_id:n});break}}}function jr(t){let e=new Set;for(let r=t.length-1;r>=0;r--)t[r].role==="tool"&&t[r].tool_call_id&&(e.has(t[r].tool_call_id)?t.splice(r,1):e.add(t[r].tool_call_id))}function Hr(t){for(let e=t.length-1;e>0;e--){let r=t[e],n=t[e-1];r.role===n.role&&(r.role==="user"||r.role==="system")&&typeof r.content=="string"&&typeof n.content=="string"&&!r.tool_call_id&&!n.tool_call_id&&(n.content=n.content+`
|
|
349
|
+
`+r.content,t.splice(e,1))}}function P(t){let e=0;for(let r of t)e+=qr(r);return Math.ceil(e/4)}function qr(t){if(t.content===null)return 0;if(typeof t.content=="string")return t.content.length;let e=0;for(let r of t.content)e+=r.text?.length??0,r.image_url&&(e+=200);return e}function Wr(t){return t.map(e=>e.role!=="tool"||typeof e.content!="string"||e.content.length<=512?e:{...e,content:e.content.slice(0,512)+`
|
|
350
|
+
...[truncated]`})}function yn(t,e){let r=t.filter(s=>s.role==="system"),o=t.filter(s=>s.role!=="system").slice(-e);return[...r,...o]}var Jr="Summarize the following conversation concisely. Preserve key facts, decisions, tool results, and user preferences. Output only the summary.";async function Vr(t,e,r){let n=t.filter(l=>l.role==="system"),o=t.filter(l=>l.role!=="system");if(o.length<=4)return t;let s=o.slice(0,-4),i=o.slice(-4),a=s.map(l=>{let d=l.content===null?"":typeof l.content=="string"?l.content:l.content.map(u=>u.text??"").join("");return`[${l.role}]: ${d}`}).join(`
|
|
351
|
+
`),c={model:r,messages:[{role:"system",content:Jr},{role:"user",content:a}],maxTokens:1024,temperature:0};try{let l=await e.complete(c),d={role:"system",content:`[Compacted ${s.length} messages]
|
|
352
|
+
${l.content}`};return[...n,d,...i]}catch{return t}}async function*qe(t,e){let r=e.contextWindowTokens??2e5,n=e.sessionId,o=Date.now(),s=t,i=P(s)/r;if(i<.7)return{messages:s,stage:0,strategy:"none"};let a=P(s);if(s=Wr(s),i=P(s)/r,yield{type:"context:overflow",timestamp:o,sessionId:n,tokensUsed:a,tokenBudget:r},yield{type:"context:truncating",timestamp:o,sessionId:n,beforeTokens:a,afterTokens:P(s),strategy:"trim_tool_results"},i<.7)return{messages:s,stage:1,strategy:"trim_tool_results"};let c=P(s);if(s=yn(s,10),i=P(s)/r,yield{type:"context:truncating",timestamp:o,sessionId:n,beforeTokens:c,afterTokens:P(s),strategy:"remove_oldest"},i<.7)return{messages:s,stage:2,strategy:"remove_oldest"};if(e.utilityProvider){let d=P(s);if(s=await Vr(s,e.utilityProvider,e.utilityModel??"claude-haiku-4-5-20251001"),i=P(s)/r,yield{type:"context:truncating",timestamp:o,sessionId:n,beforeTokens:d,afterTokens:P(s),strategy:"llm_compaction"},i<.7)return{messages:s,stage:3,strategy:"llm_compaction"}}let l=P(s);return s=yn(s,2),yield{type:"context:truncating",timestamp:o,sessionId:n,beforeTokens:l,afterTokens:P(s),strategy:"emergency_truncation"},{messages:s,stage:4,strategy:"emergency_truncation"}}function We(t,e){let r=e??2e5,n=P(t);return{ratio:n/r,overLimit:n/r>=.7}}var hn={blocked:!1,warning:!1};function Je(t){let e=t.function.name+":"+t.function.arguments;return Bun.hash(e).toString(16)}function Gr(t){return Bun.hash(t).toString(16)}var V=class{maxTotal;history=[];callCounts=new Map;pairCounts=new Map;constructor(e=25){this.maxTotal=e}check(e){for(let n of e){let o=Je(n);this.history.push(o),this.callCounts.set(o,(this.callCounts.get(o)??0)+1)}if(this.history.length>=this.maxTotal)return{blocked:!0,warning:!1,reason:`Max total calls reached (${this.maxTotal})`};for(let n of e){let o=Je(n),s=this.callCounts.get(o);if(s>=5)return{blocked:!0,warning:!1,reason:`Identical call repeated ${s} times`};if(s>=3){let i=this.detectPingPong();return i||{blocked:!1,warning:!0,reason:`Identical call repeated ${s} times`}}}let r=this.detectPingPong();return r||hn}recordResult(e,r){let n=Je(e)+":"+Gr(r),o=(this.pairCounts.get(n)??0)+1;return this.pairCounts.set(n,o),o>=3?{blocked:!0,warning:!1,reason:`Same call+result pair repeated ${o} times`}:o>=2?{blocked:!1,warning:!0,reason:`Same call+result pair repeated ${o} times`}:hn}reset(){this.history=[],this.callCounts.clear(),this.pairCounts.clear()}totalCalls(){return this.history.length}detectPingPong(){let e=this.history;if(e.length<6)return null;let r=e.length,n=e[r-1],o=e[r-2];if(n===o)return null;let s=1;for(let i=r-3;i>=0&&!(i-1<0);i-=2)if(e[i]===n&&e[i-1]===o)s++;else break;return s>=3?{blocked:!0,warning:!1,reason:`Ping-pong pattern detected (${s} alternations)`}:null}};var Xr=0;function Kr(){return`task-${Date.now()}-${++Xr}`}var ie=class{_tasks=[];get tasks(){return this._tasks}add(e){let r={id:Kr(),title:e,status:"pending"};return this._tasks.push(r),r}update(e,r){let n=this._tasks.find(o=>o.id===e);n&&(n.status=r)}current(){let e=this._tasks.find(r=>r.status==="in_progress");return e||this._tasks.find(r=>r.status==="pending")}plan(e){let r=[];for(let n of e)r.push(this.add(n));return r}complete(e){this.update(e,"done")}block(e){this.update(e,"blocked")}summary(){let e=0,r=0,n=0,o=0;for(let s of this._tasks)switch(s.status){case"pending":e++;break;case"in_progress":r++;break;case"done":n++;break;case"blocked":o++;break}return{total:this._tasks.length,pending:e,inProgress:r,done:n,blocked:o}}};async function*Ve(t){let{sessionId:e,tracker:r,toolLog:n,brainArtifacts:o,conversationId:s,userId:i}=t;for(let f of r.tasks)f.status==="in_progress"&&r.update(f.id,"blocked");let a=0,c=0,l=0;for(let f of r.tasks)switch(f.status){case"done":a++;break;case"pending":c++;break;case"blocked":l++;break}let d=r.tasks.length,u=n.map(f=>`${f.tool}:${f.ok?"ok":"fail"}`).join(", ");if(o&&s&&i){let f=r.tasks.filter(T=>T.status==="pending"||T.status==="blocked");if(f.length>0){let T=["# Open Tasks (from wrapup)","",...f.map(v=>`- [${v.status}] ${v.title}`),"",`Session: ${e}`,`Timestamp: ${new Date().toISOString()}`].join(`
|
|
353
|
+
`);try{await o.save(s,i,"open-tasks.md",T)}catch{}}}yield{type:"wrapup:complete",timestamp:Date.now(),sessionId:e,summary:`Completed ${a}/${d} tasks (${c} pending, ${l} blocked). Tools: ${u||"none"}`}}var ke=class{blocks=new Map;nextId=1;create(e,r){let n=`blk-${this.nextId++}`;return this.blocks.set(n,{type:e,data:r}),n}append(e,r){let n=this.blocks.get(e);return n?(typeof n.data=="string"&&(n.data+=r),{op:"append",path:"data",value:r}):null}get(e){return this.blocks.get(e)}get size(){return this.blocks.size}};async function*ae(t,e){let{providers:r,toolRouter:n,jobQueue:o,extensions:s,sessionId:i,maxTurns:a=20,tokenBudget:c=128e3,contextWindowTokens:l=2e5,initialMode:d="conversation",systemPrompt:u,permissions:f=[],classifyQuery:T,emitBlocks:v=!1,readOnlyTools:g=new Set}=t,p=d,m=0,y=0,E=[],U=new ke,S=new V(a),$=new ie,R=[],M={sessionId:i,mode:p,turnNumber:0,tokenBudget:c,tokensUsed:0,activeTools:[]};if(yield{type:"agent:start",timestamp:Date.now(),sessionId:i,mode:p,input:e},u&&E.push({role:"system",content:u}),e.text&&E.push({role:"user",content:e.text}),o)try{let _=await o.getJobsByStatus("queued");_.length>0&&E.push({role:"system",content:`[System] ${_.length} pending job(s) in queue: ${_.map(F=>`${F.type}(${F.id})`).join(", ")}`})}catch{}let $e=Qr(E);if(y+=$e,yield{type:"context:built",timestamp:Date.now(),sessionId:i,tokenCount:$e,messageCount:E.length},T&&e.text)try{let _=await T(e.text,M);if(yield{type:"query:classified",timestamp:Date.now(),sessionId:i,queryId:`q-${i}-${m}`,classification:_.classification,standaloneQuery:_.standaloneQuery,skipAgent:_.skipAgent},_.skipAgent&&_.directResponse){yield*Tn(_.directResponse,U,v,i,0),yield{type:"response:final",timestamp:Date.now(),sessionId:i,content:_.directResponse,usage:{inputTokens:$e,outputTokens:Yr(_.directResponse)},finishReason:"stop"},yield{type:"agent:end",timestamp:Date.now(),sessionId:i,reason:"complete",totalTurns:0,totalTokens:y};return}}catch{}for(;m<a;){if(m++,M.turnNumber=m,M.mode=p,M.tokensUsed=y,se(E),We(E,l).overLimit){let x=qe(E,{contextWindowTokens:l,utilityProvider:r.getHealthy("utility")??void 0,sessionId:i}),H;for(;;){let Z=await x.next();if(Z.done){H=Z.value;break}yield Z.value}E.length=0,E.push(...H.messages)}if(y>=c){yield{type:"context:overflow",timestamp:Date.now(),sessionId:i,tokensUsed:y,tokenBudget:c};break}let F=r.getHealthy("chat");if(!F){yield{type:"error",timestamp:Date.now(),sessionId:i,error:`No healthy provider available for mode "${p}"`,recoverable:!1};break}let Ue={mode:p,permissions:f},nn=n.listAvailable(Ue);M.activeTools=nn.map(x=>x.name);let rn=nn.map(x=>({type:"function",function:{name:x.name,description:x.description,parameters:x.parameters?Zr(x.parameters):void 0}}));s&&await s.dispatch("prompt:build",{sessionId:i,data:{messages:E,mode:p,turn:m},messages:E.map(x=>({role:x.role,content:typeof x.content=="string"?x.content:""}))});let on={messages:[...E],tools:rn.length>0?rn:void 0,temperature:p==="code"?.2:.7},k;try{k=await F.complete(on)}catch(x){let H=x instanceof Error?x.message:String(x);yield{type:"error",timestamp:Date.now(),sessionId:i,error:`LLM call failed: ${H}`,code:"LLM_ERROR",recoverable:!0};break}if(k.usage&&(y+=k.usage.inputTokens+k.usage.outputTokens,yield{type:"cost:tracked",timestamp:Date.now(),sessionId:i,provider:F.id,model:on.model??"default",inputTokens:k.usage.inputTokens,outputTokens:k.usage.outputTokens,estimatedCost:zr(k.usage.inputTokens,k.usage.outputTokens)}),k.content&&(yield*Tn(k.content,U,v,i,m-1),E.push({role:"assistant",content:k.content})),k.toolCalls&&k.toolCalls.length>0){E.push({role:"assistant",content:null,tool_calls:k.toolCalls});let x=S.check(k.toolCalls);if(x.blocked){yield{type:"loop:blocked",timestamp:Date.now(),sessionId:i,turnCount:m,reason:x.reason??"Loop guard blocked"};break}x.warning&&(yield{type:"loop:warning",timestamp:Date.now(),sessionId:i,turnCount:m,pattern:x.reason??"repetition_detected"});let H=k.toolCalls.filter(C=>g.has(C.function.name)),Z=k.toolCalls.filter(C=>!g.has(C.function.name));if(H.length>0){let C=H.map(async O=>{let b=vn(O.function.arguments);if(s&&(await s.dispatch("tool:before",{sessionId:i,data:{toolName:O.function.name,arguments:b}})).action==="halt")return{tc:O,toolResult:{name:O.function.name,error:"Blocked by extension"},args:b,durationMs:0};let I=Date.now(),K=await n.route({name:O.function.name,arguments:b},Ue);return{tc:O,toolResult:K,args:b,durationMs:Date.now()-I}}),ee=await Promise.allSettled(C);for(let O of ee){if(O.status!=="fulfilled")continue;let{tc:b,toolResult:I,args:K,durationMs:N}=O.value;if(R.push({tool:b.function.name,ok:!I.error}),yield{type:"tool:start",timestamp:Date.now(),sessionId:i,toolName:b.function.name,arguments:K,callId:b.id},yield{type:"tool:result",timestamp:Date.now(),sessionId:i,toolName:b.function.name,callId:b.id,result:I.result,error:I.error,durationMs:N},s&&await s.dispatch("tool:after",{sessionId:i,data:{toolName:b.function.name,result:I,durationMs:N}}),v){let ir=U.create(I.error?"error":"tool_result",I.error??I.result);yield{type:"block:emitted",timestamp:Date.now(),sessionId:i,blockId:ir,blockType:I.error?"error":"tool_result",data:I.error??I.result}}let sn=JSON.stringify(I.error??I.result);S.recordResult(b,sn),E.push({role:"tool",content:sn,tool_call_id:b.id})}}for(let C of Z){let ee=vn(C.function.arguments);if(s&&(await s.dispatch("tool:before",{sessionId:i,data:{toolName:C.function.name,arguments:ee}})).action==="halt"){R.push({tool:C.function.name,ok:!1}),E.push({role:"tool",content:'{"error":"Blocked by extension"}',tool_call_id:C.id});continue}yield{type:"tool:start",timestamp:Date.now(),sessionId:i,toolName:C.function.name,arguments:ee,callId:C.id};let O=Date.now(),b=await n.route({name:C.function.name,arguments:ee},Ue),I=Date.now()-O;if(R.push({tool:C.function.name,ok:!b.error}),yield{type:"tool:result",timestamp:Date.now(),sessionId:i,toolName:C.function.name,callId:C.id,result:b.result,error:b.error,durationMs:I},s&&await s.dispatch("tool:after",{sessionId:i,data:{toolName:C.function.name,result:b,durationMs:I}}),v){let N=U.create(b.error?"error":"tool_result",b.error??b.result);yield{type:"block:emitted",timestamp:Date.now(),sessionId:i,blockId:N,blockType:b.error?"error":"tool_result",data:b.error??b.result}}let K=JSON.stringify(b.error??b.result);if(S.recordResult(C,K),b.result&&typeof b.result=="object"){let N=b.result;N.id&&N.status==="queued"&&N.type&&(yield{type:"job:enqueued",timestamp:Date.now(),sessionId:i,jobId:N.id,jobType:N.type,jobPriority:N.priority??"normal"})}E.push({role:"tool",content:K,tool_call_id:C.id})}continue}if(k.finishReason==="stop"||k.finishReason===null){if(p==="task"&&k.content?.includes("[PLAN]")){let x=p;p="code",yield{type:"mode:changed",timestamp:Date.now(),sessionId:i,from:x,to:p,reason:"Planning phase complete, moving to execution"};continue}yield{type:"response:final",timestamp:Date.now(),sessionId:i,content:k.content??"",usage:k.usage??{inputTokens:0,outputTokens:0},finishReason:k.finishReason};break}if(k.finishReason==="length"){yield{type:"context:overflow",timestamp:Date.now(),sessionId:i,tokensUsed:y,tokenBudget:c};break}}if(m>=a){yield{type:"loop:warning",timestamp:Date.now(),sessionId:i,turnCount:m,pattern:"max_turns_reached"};let _=Ve({sessionId:i,tracker:$,toolLog:R});for await(let F of _)yield F}yield{type:"agent:end",timestamp:Date.now(),sessionId:i,reason:m>=a?"timeout":"complete",totalTurns:m,totalTokens:y}}function vn(t){try{return JSON.parse(t)}catch{return{}}}function*Tn(t,e,r,n,o){if(r){let s=e.create("text",t);yield{type:"block:emitted",timestamp:Date.now(),sessionId:n,blockId:s,blockType:"text",data:t}}else yield{type:"token",timestamp:Date.now(),sessionId:n,content:t,index:o}}function Qr(t){let e=0;for(let r of t)if(typeof r.content=="string")e+=r.content.length;else if(Array.isArray(r.content))for(let n of r.content)n.text&&(e+=n.text.length);return Math.ceil(e/4)}function Yr(t){return Math.ceil(t.length/4)}function zr(t,e){return t/1e6*3+e/1e6*15}function Zr(t){let e={},r=[];for(let[n,o]of Object.entries(t))e[n]={type:o.type,description:o.description},o.required&&r.push(n);return{type:"object",properties:e,required:r}}var eo={type:"object",properties:{intent:{type:"string",enum:["factual","creative","analytical","conversational","code","search"],description:"Primary intent of the query"},confidence:{type:"number",description:"Confidence score 0-1"},standaloneQuery:{type:"string",description:"Rewritten standalone version of the query (for follow-ups)"},skipAgent:{type:"boolean",description:"True if the query can be answered directly without tools"},directResponse:{type:"string",description:"Direct response if skipAgent is true, omit otherwise"}},required:["intent","confidence","standaloneQuery","skipAgent"],additionalProperties:!1},bn=`You are a query classifier. Analyze the user's query and determine:
|
|
354
|
+
1. The primary intent (factual, creative, analytical, conversational, code, search)
|
|
355
|
+
2. Whether it can be answered directly without tools (simple greetings, factual questions you know)
|
|
356
|
+
3. A standalone rewrite if the query references prior context
|
|
357
|
+
|
|
358
|
+
For trivial queries like "hello", "thanks", "what is 2+2", set skipAgent=true and provide a directResponse.
|
|
359
|
+
For anything requiring tools, code execution, file access, or research, set skipAgent=false.`;function Ge(t){return async(e,r)=>{let n=ro(e);if(n)return n;if(t.generateObject){let s=await t.generateObject({messages:[{role:"system",content:bn},{role:"user",content:e}],schema:eo,schemaName:"query_classification",temperature:0,maxTokens:256});return En(s,e)}let o=await t.complete({messages:[{role:"system",content:bn+`
|
|
360
|
+
|
|
361
|
+
Respond with JSON only.`},{role:"user",content:e}],temperature:0,maxTokens:256});try{let s=JSON.parse(o.content);return En(s,e)}catch{return{classification:{intent:"conversational",confidence:.5},standaloneQuery:e,skipAgent:!1}}}}var to=/^(hi|hello|hey|howdy|greetings|yo|sup)\b[!?.]*$/i,no=/^(thanks?|thank\s*you|thx|ty)\b[!?.]*$/i;function ro(t){let e=t.trim();return to.test(e)?{classification:{intent:"conversational",confidence:1},standaloneQuery:e,skipAgent:!0,directResponse:"Hello! How can I help you today?"}:no.test(e)?{classification:{intent:"conversational",confidence:1},standaloneQuery:e,skipAgent:!0,directResponse:"You're welcome! Let me know if you need anything else."}:null}function En(t,e){return{classification:{intent:t.intent,confidence:Math.max(0,Math.min(1,t.confidence))},standaloneQuery:t.standaloneQuery||e,skipAgent:t.skipAgent,directResponse:t.skipAgent?t.directResponse:void 0}}function Xe(t){t.register({id:"fenix.session-repair",name:"Session Repair",setup(e){e.registerHook("prompt:build",async r=>{let n=r.data.messages;return n&&se(n),{action:"continue",data:r.data}},{id:"session:repair",priority:5})}})}function Ke(t){t.register({id:"fenix.logging",name:"Event Logging",setup(e){e.registerHook("event",async r=>(r.event&&console.log(`[event] ${r.event.type}`,r.event.sessionId),{action:"continue",data:r.data}),{id:"event:log",priority:10})}})}function Qe(t,e){let r=new V(e);t.register({id:"fenix.loop-guard",name:"Loop Guard",setup(n){n.registerHook("tool:before",async o=>{let s=o.data.toolCalls;if(s&&s.length>0){let i=r.check(s);if(i.blocked)return{action:"halt",data:{reason:i.reason}}}return{action:"continue",data:o.data}},{id:"loop:guard",priority:15})}})}function kn(t){let e=t.split(".");if(e.length!==4)return null;let r=0;for(let n of e){let o=n.startsWith("0")&&n.length>1?parseInt(n,8):parseInt(n,10);if(Number.isNaN(o)||o<0||o>255)return null;r=r<<8|o}return r>>>0}var oo=[{base:0,mask:4278190080,label:"Blocked IP range"},{base:167772160,mask:4278190080,label:"private (10.0.0.0/8)"},{base:2886729728,mask:4293918720,label:"private (172.16.0.0/12)"},{base:3232235520,mask:4294901760,label:"private (192.168.0.0/16)"},{base:2130706432,mask:4278190080,label:"loopback (127.0.0.0/8)"},{base:2851995648,mask:4294901760,label:"linkLocal (169.254.0.0/16)"}];function Ye(t){for(let e of oo)if((t&e.mask)>>>0===e.base)return e.label;return null}function so(t){let e=t.replace(/^\[|]$/g,"").toLowerCase(),r=e.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/);if(r){let o=kn(r[1]);if(o!==null){let s=Ye(o);if(s)return`IPv6-mapped ${s}`}}let n=e.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);if(n){let o=parseInt(n[1],16),s=parseInt(n[2],16),i=(o<<16|s)>>>0,a=Ye(i);if(a)return`IPv6-mapped ${a}`}return e==="::1"?"IPv6 loopback":/^fc/.test(e)||/^fd/.test(e)?"fc00::/7 unique local":/^fe[89ab]/.test(e)?"fe80::/10 link-local":null}function io(t){let e=kn(t);if(e!==null){let r=Ye(e);return r?{safe:!1,reason:`IP in ${r}`}:{safe:!0}}if(t.startsWith("[")||t.includes(":")){let r=so(t);return r?{safe:!1,reason:r}:{safe:!0}}return{safe:!0}}var ao=new Set(["file:","data:","javascript:","ftp:","gopher:"]),co=new Set(["http:","https:"]);function Sn(t){if(t.includes("\0"))return{safe:!1,reason:"URL contains null bytes"};if(/\.\.[/\\]/.test(t))return{safe:!1,reason:"URL contains path traversal"};let e;try{e=new URL(t)}catch{return{safe:!1,reason:"Invalid URL"}}return ao.has(e.protocol)?{safe:!1,reason:`Blocked protocol: ${e.protocol}`}:co.has(e.protocol)?io(e.hostname):{safe:!1,reason:`Unsupported protocol: ${e.protocol}`}}function ze(t){t.register({id:"fenix.ssrf-protection",name:"SSRF Protection",setup(e){e.registerHook("tool:before",async r=>{let n=r.data.url;if(n){let o=Sn(n);if(!o.safe)return{action:"halt",data:{reason:o.reason}}}return{action:"continue",data:r.data}},{id:"security:ssrf",priority:25})}})}function Ze(t,e=6e4,r=60){let n=new Map;t.register({id:"fenix.rate-limiting",name:"Rate Limiting",setup(o){o.registerHook("tool:before",async s=>{let i=s.data.userId,a=s.data.action;if(!i)return{action:"continue",data:s.data};let c=`${i}:${a??"default"}`,l=Date.now(),d=n.get(c)?.filter(u=>u>l-e)??[];return d.push(l),n.set(c,d),d.length>r?{action:"halt",data:{reason:`Rate limit exceeded: ${r}/${e}ms`}}:{action:"continue",data:s.data}},{id:"security:rate-limit",priority:30})}})}var lo=new Set(["PATH","HOME","TERM","USER","SHELL","PWD","LANG","NODE_ENV","BUN_ENV"]);function uo(t){return lo.has(t)||t.startsWith("LC_")}var po=[{re:/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g,label:"${VAR}",group:1},{re:/(?<![\\$\{])\$([A-Za-z_][A-Za-z0-9_]*)/g,label:"$VAR",group:1},{re:/process\.env\.([A-Za-z_][A-Za-z0-9_]*)/g,label:"process.env.VAR",group:1},{re:/process\.env\[['"]([A-Za-z_][A-Za-z0-9_]*)['"]\]/g,label:"process.env['VAR']",group:1},{re:/os\.environ\[['"]([A-Za-z_][A-Za-z0-9_]*)['"]\]/g,label:"os.environ['VAR']",group:1},{re:/os\.environ\.get\(\s*['"]([A-Za-z_][A-Za-z0-9_]*)['"]/g,label:"os.environ.get('VAR')",group:1},{re:/ENV\[['"]([A-Za-z_][A-Za-z0-9_]*)['"]\]/g,label:"ENV['VAR']",group:1},{re:/ENV\.fetch\(\s*['"]([A-Za-z_][A-Za-z0-9_]*)['"]/g,label:"ENV.fetch('VAR')",group:1}];function xn(t,e="warn"){let r=t.split(`
|
|
362
|
+
`),n=[],o=new Set;for(let i=0;i<r.length;i++){let a=r[i];for(let c of po){c.re.lastIndex=0;let l;for(;(l=c.re.exec(a))!==null;){let d=l[c.group],u=`${i}:${d}:${c.label}`;uo(d)||o.has(u)||(o.add(u),n.push({variable:d,line:i+1,pattern:c.label}))}}}let s=n.length===0;return{safe:s,action:e,leaks:n,blocked:!s&&e==="block"}}function et(t){t.register({id:"fenix.shell-bleed",name:"Shell Bleed Detection",setup(e){e.registerHook("tool:before",async r=>{let n=r.data.script;if(n){let o=xn(n);if(!o.safe)return{action:"halt",data:{reason:`Shell bleed: ${o.leaks.map(s=>s.variable).join(", ")}`}}}return{action:"continue",data:r.data}},{id:"security:shell-bleed",priority:35})}})}var mo="Summarize the following conversation concisely. Preserve key facts, decisions, tool results, and user preferences. Output only the summary, no preamble.";function tt(t){let e=0;for(let r of t)if(r.content!==null)if(typeof r.content=="string")e+=r.content.length;else for(let n of r.content)e+=n.text?.length??0;return Math.ceil(e/4)}function nt(t,e){return t.length>30?!0:tt(t)/e.contextWindowTokens>.7}function go(t,e){return e.utilityProvider?t.length>=50?"hybrid":"summarize-all":"summarize-oldest"}function fo(t){return t.map(e=>{let r=e.content===null?"":typeof e.content=="string"?e.content:e.content.map(n=>n.text??"").join("");return`[${e.role}]: ${r}`}).join(`
|
|
363
|
+
`)}async function wn(t,e,r){return(await e.complete({model:r,messages:[{role:"system",content:mo},{role:"user",content:fo(t)}],maxTokens:1024,temperature:0})).content}async function yo(t,e,r){return wn(t,e,r)}async function ho(t){let e=t[0],r=t[t.length-1],n=e?.content===null?"":typeof e?.content=="string"?e.content:"[complex content]",o=r?.content===null?"":typeof r?.content=="string"?r.content:"[complex content]";return`[Compacted: ${t.length} messages removed]
|
|
364
|
+
First: ${n.slice(0,200)}
|
|
365
|
+
Last: ${o.slice(0,200)}`}async function vo(t,e,r){let n=[];for(let s=0;s<t.length;s+=10)n.push(t.slice(s,s+10));return(await Promise.all(n.map(s=>wn(s,e,r)))).join(`
|
|
366
|
+
|
|
367
|
+
`)}async function rt(t,e){let r=go(t,e),n=e.utilityModel??"claude-haiku-4-5-20251001",o=tt(t);if(t.length<=6)return{messages:t,removed:0,strategy:r,beforeTokens:o,afterTokens:o};let s=t.slice(0,-6),i=t.slice(-6),a;switch(r){case"summarize-all":a=await yo(s,e.utilityProvider,n);break;case"hybrid":a=await vo(s,e.utilityProvider,n);break;case"summarize-oldest":a=await ho(s);break}let l=[{role:"system",content:`[Session Summary]
|
|
368
|
+
${a}`},...i],d=tt(l);return{messages:l,removed:s.length,strategy:r,beforeTokens:o,afterTokens:d}}function ot(t){t.register({id:"fenix.context-survival",name:"Context Survival",setup(e){e.registerHook("prompt:build",async r=>{let n=r.data.messages,o=r.data.contextWindowTokens;if(!n)return{action:"continue",data:r.data};let s={contextWindowTokens:o??2e5};if(!nt(n,s))return{action:"continue",data:{...r.data,compacted:!1}};let i=await rt(n,s);return{action:"continue",data:{...r.data,messages:i.messages,compacted:!0}}},{id:"context:survival",priority:45})}})}var st={steeringRules:.2,memories:.4,orientContext:.2,brainArtifacts:.2};function Se(t){return Math.ceil(t.length/4)}function it(t,e){let r=Math.max(0,t-200),o=Object.keys(st).filter(a=>e[a]>0);if(o.length===0)return{identity:200,steeringRules:0,memories:0,orientContext:0,brainArtifacts:0,total:200};let s=o.reduce((a,c)=>a+st[c],0),i={identity:200,steeringRules:0,memories:0,orientContext:0,brainArtifacts:0,total:0};for(let a of o)i[a]=Math.floor(r*(st[a]/s));return i.total=i.identity+i.steeringRules+i.memories+i.orientContext+i.brainArtifacts,i}function xe(t,e){if(e<=0)return"";if(Se(t)<=e)return t;let n=e*4,o=t.slice(0,n),s=o.lastIndexOf(`
|
|
369
|
+
`);return(s>0?o.slice(0,s):o)+`
|
|
370
|
+
[...truncated]`}function at(t){t.register({id:"fenix.context-budget",name:"Context Budget",setup(e){e.registerHook("prompt:build",async r=>{let n=r.data.sections,o=r.data.totalBudget;if(!n||!o)return{action:"continue",data:r.data};let s=Object.fromEntries(Object.entries(n).map(([c,l])=>[c,Se(l)])),i=it(o,s),a=Object.fromEntries(Object.entries(n).map(([c,l])=>{let d=i[c]??o;return[c,xe(l,d)]}));return{action:"continue",data:{...r.data,sections:a,allocation:i}}},{id:"context:budget",priority:50})}})}function ct(t={}){let e=[];return{id:"fenix.job-dispatch",name:"Job Dispatch Tracker",version:"1.0.0",setup(r){r.registerHook("event",async n=>{let o=n.event;if(!o||o.type!=="tool:result")return{action:"continue"};let s=o.result;if(s&&typeof s=="object"){let i=s;if(i.id&&i.status==="queued"&&i.type){let a={id:i.id,type:i.type,toolName:o.toolName,timestamp:o.timestamp};return e.push(a),t.onJobDispatched&&t.onJobDispatched({id:a.id,type:a.type,toolName:a.toolName}),{action:"continue",data:{lastDispatchedJob:a,dispatchedJobCount:e.length}}}}return{action:"continue"}},{id:"fenix.job-dispatch.tracker",priority:65,eventTypes:["tool:result"]})},teardown(){e.length=0}}}function lt(t){let e=[`# Skill: ${t.name}`,t.description,"",t.body];return t.files.length>0&&e.push("","Files:",...t.files.map(r=>`- ${r}`)),e.join(`
|
|
371
|
+
`)}function dt(t,e,r=3){let n=e.toLowerCase().split(/\s+/).filter(Boolean);return n.length===0?[]:t.map(s=>{let i=`${s.name} ${s.description}`.toLowerCase(),a=n.reduce((c,l)=>c+(i.includes(l)?1:0),0);return{skill:s,score:a}}).filter(s=>s.score>0).sort((s,i)=>i.score-s.score).slice(0,r).map(s=>lt(s.skill))}function ut(t){let e=t.maxSkills??2;return{id:"fenix.skill-loader",name:"Skill Loader",version:"1.0.0",setup(r){r.registerHook("prompt:build",async n=>{let o=n.data.query;if(!o||t.skills.length===0)return{action:"continue"};let s=dt(t.skills,o,e);if(s.length===0)return{action:"continue"};if(n.messages)for(let i of s)n.messages.push({role:"system",content:`[Skill Context]
|
|
372
|
+
${i}`});return t.onSkillsLoaded&&t.onSkillsLoaded(s),{action:"continue",data:{loadedSkills:s.length,skillNames:s.map(i=>i.match(/^# Skill: (.+)$/m)?.[1]??"unknown")}}},{id:"fenix.skill-loader.prompt-build",priority:70})}}}function pt(t){return[{name:"memory.search",description:"Search user memory for relevant facts, preferences, and knowledge by semantic similarity",parameters:{userId:{type:"string",required:!0,description:"User ID to search memories for"},query:{type:"string",required:!0,description:"Natural language search query"},limit:{type:"number",description:"Max results to return (default: 5)"}},handler:async e=>(await t.search(e.userId,e.query,e.limit??5)).map(n=>({id:n.segment.id,content:n.segment.content,category:n.segment.category,score:n.score,heat:n.segment.heat}))},{name:"memory.expand",description:"Expand a memory segment with related context and connections",parameters:{userId:{type:"string",required:!0,description:"User ID"},query:{type:"string",required:!0,description:"Topic to expand on"},limit:{type:"number",description:"Max related segments (default: 10)"}},handler:async e=>{let r=await t.search(e.userId,e.query,e.limit??10);return{topic:e.query,segments:r.map(n=>({content:n.segment.content,category:n.segment.category,score:n.score})),count:r.length}}},{name:"memory.context",description:"Get the user's profile summary and recent memory context",parameters:{userId:{type:"string",required:!0,description:"User ID"}},handler:async e=>{let r=await t.getProfile(e.userId);return{userId:e.userId,profile:r??"No profile available"}}},{name:"memory.save",description:"Save a new memory segment (fact, preference, experience, or knowledge)",parameters:{userId:{type:"string",required:!0,description:"User ID"},content:{type:"string",required:!0,description:"Memory content to save"},category:{type:"string",required:!0,description:"fact | preference | experience | knowledge"}},requiredPermissions:["memory:write"],handler:async e=>{let r=await t.save(e.userId,e.content,e.category);return{id:r.id,saved:!0,category:r.category}}},{name:"memory.forget",description:"Remove a specific memory segment by ID",parameters:{segmentId:{type:"string",required:!0,description:"Memory segment ID to remove"}},requiredPermissions:["memory:write"],handler:async e=>({deleted:await t.forget(e.segmentId),segmentId:e.segmentId})},{name:"memory.list",description:"List memory segments for a user, optionally filtered by category",parameters:{userId:{type:"string",required:!0,description:"User ID"},category:{type:"string",description:"Filter by: fact | preference | experience | knowledge"},limit:{type:"number",description:"Max results (default: 20)"}},handler:async e=>(await t.list(e.userId,e.category,e.limit??20)).map(n=>({id:n.id,content:n.content,category:n.category,heat:n.heat,createdAt:n.createdAt}))},{name:"memory.graph",description:"Query the knowledge graph for entity relationships",parameters:{userId:{type:"string",required:!0,description:"User ID"},entity:{type:"string",required:!0,description:"Entity name to query"}},handler:async e=>t.graphQuery?t.graphQuery(e.userId,e.entity):{error:"Knowledge graph not available"}}]}function mt(t){return[{name:"web.search",description:"Search the web for information. Uses primary search provider with fallback on failure",parameters:{query:{type:"string",required:!0,description:"Search query"},limit:{type:"number",description:"Max results (default: 5)"}},handler:async e=>{let r=e.query,n=e.limit??5;try{return await t.primary.search(r,{limit:n})}catch(o){if(!t.fallback)throw o;try{return await t.fallback.search(r,{limit:n})}catch{throw o}}}},{name:"web.fetch",description:"Fetch and extract content from a URL. Returns cleaned page text",parameters:{url:{type:"string",required:!0,description:"URL to fetch content from"}},handler:async e=>t.fetcher.fetch(e.url)}]}function gt(t){return[{name:"code.execute",description:"Execute code in a sandboxed environment. Supports JavaScript, Python, and shell",parameters:{code:{type:"string",required:!0,description:"Code to execute"},language:{type:"string",required:!0,description:"Language: javascript | python | shell"},timeout:{type:"number",description:"Timeout in ms (default: 30000)"}},requiredPermissions:["code:execute"],handler:async e=>t.execute(e.code,e.language,e.timeout??3e4)},{name:"code.analyze",description:"Analyze code for complexity, patterns, and potential issues",parameters:{code:{type:"string",required:!0,description:"Code to analyze"},language:{type:"string",required:!0,description:"Programming language"}},handler:async e=>t.analyze(e.code,e.language)},{name:"code.explain",description:"Generate a human-readable explanation of code",parameters:{code:{type:"string",required:!0,description:"Code to explain"},language:{type:"string",required:!0,description:"Programming language"}},handler:async e=>({explanation:await t.explain(e.code,e.language),language:e.language})}]}function ft(t){return[{name:"files.read",description:"Read the contents of a file",parameters:{path:{type:"string",required:!0,description:"File path to read"}},handler:async e=>{let r=await t.read(e.path);return{path:e.path,content:r}}},{name:"files.write",description:"Write content to a file (creates or overwrites)",parameters:{path:{type:"string",required:!0,description:"File path to write to"},content:{type:"string",required:!0,description:"Content to write"}},requiredPermissions:["files:write"],handler:async e=>t.write(e.path,e.content)},{name:"files.list",description:"List files and directories at a given path",parameters:{directory:{type:"string",required:!0,description:"Directory path to list"},recursive:{type:"boolean",description:"Include subdirectories recursively (default: false)"}},handler:async e=>(await t.list(e.directory,e.recursive)).map(n=>({path:n.path,name:n.name,size:n.size,isDirectory:n.isDirectory,modifiedAt:n.modifiedAt}))},{name:"files.search",description:"Search for text patterns across files in a directory",parameters:{directory:{type:"string",required:!0,description:"Directory to search in"},pattern:{type:"string",required:!0,description:"Search pattern (regex supported)"},limit:{type:"number",description:"Max results (default: 20)"}},handler:async e=>t.search(e.directory,e.pattern,{limit:e.limit??20})}]}function yt(t){return[{name:"schedule.create",description:"Create a scheduled task. Supports one-time (runAt) or recurring (cron) schedules",parameters:{name:{type:"string",required:!0,description:"Schedule name/description"},cron:{type:"string",description:"Cron expression for recurring (e.g. '0 9 * * *')"},runAt:{type:"string",description:"ISO 8601 datetime for one-time execution"},payload:{type:"object",required:!0,description:"Data to pass to the scheduled task"}},requiredPermissions:["schedule:write"],handler:async e=>{let r=await t.create({name:e.name,cron:e.cron,runAt:e.runAt,payload:e.payload??{}});return{id:r.id,name:r.name,status:r.status,cron:r.cron,runAt:r.runAt}}},{name:"schedule.list",description:"List scheduled tasks, optionally filtered by status",parameters:{status:{type:"string",description:"Filter by: active | paused | cancelled | completed"}},handler:async e=>(await t.list(e.status)).map(n=>({id:n.id,name:n.name,status:n.status,cron:n.cron,runAt:n.runAt,createdAt:n.createdAt}))},{name:"schedule.cancel",description:"Cancel a scheduled task by ID",parameters:{id:{type:"string",required:!0,description:"Schedule ID to cancel"}},requiredPermissions:["schedule:write"],handler:async e=>({cancelled:await t.cancel(e.id),id:e.id})}]}function ht(t){return[{name:"tasks.plan",description:"Create a task plan by decomposing a goal into actionable steps",parameters:{goal:{type:"string",required:!0,description:"High-level goal to accomplish"},context:{type:"string",description:"Additional context or constraints"}},handler:async e=>t.plan(e.goal,e.context)},{name:"tasks.update",description:"Update the status of a step within a task plan",parameters:{planId:{type:"string",required:!0,description:"Task plan ID"},stepId:{type:"string",required:!0,description:"Step ID within the plan"},status:{type:"string",required:!0,description:"pending | in_progress | done | skipped"},result:{type:"string",description:"Result or notes for this step"}},handler:async e=>t.update(e.planId,e.stepId,e.status,e.result)},{name:"tasks.list",description:"List task plans, optionally filtered by status",parameters:{status:{type:"string",description:"Filter by: planning | active | completed | cancelled"}},handler:async e=>t.list(e.status)},{name:"tasks.complete",description:"Mark a task plan as completed with a summary",parameters:{planId:{type:"string",required:!0,description:"Task plan ID to complete"},summary:{type:"string",required:!0,description:"Completion summary"}},handler:async e=>t.complete(e.planId,e.summary)}]}function vt(t){return[{name:"browser.navigate",description:"Navigate to a URL and return the page title and content summary",parameters:{url:{type:"string",required:!0,description:"The URL to navigate to"}},handler:async e=>t.navigate(e.url)},{name:"browser.click",description:"Click an element on the current page by CSS selector",parameters:{selector:{type:"string",required:!0,description:"CSS selector of element to click"}},handler:async e=>t.click(e.selector)},{name:"browser.type",description:"Fill an input field on the current page",parameters:{selector:{type:"string",required:!0,description:"CSS selector of the input field"},text:{type:"string",required:!0,description:"Text to type into the field"}},handler:async e=>t.type(e.selector,e.text)},{name:"browser.extract",description:"Extract cleaned page content (strips nav, ads, scripts). Optionally scope to a CSS selector",parameters:{selector:{type:"string",description:"Optional CSS selector to scope extraction"}},handler:async e=>t.extract(e.selector)},{name:"browser.screenshot",description:"Capture a screenshot of the current viewport as base64 PNG for vision analysis",handler:async()=>t.screenshot()}]}var B={maxRestartAttempts:3,baseCooldownMs:5e3,backoffMultiplier:3,maxCooldownMs:3e5,healthCheckIntervalMs:3e4},ce=class{sidecars=new Map;startFn;healthCheckFn;pendingEvents=[];constructor(e,r){this.startFn=e,this.healthCheckFn=r}add(e){this.sidecars.set(e.id,{config:e,state:"stopped",restartAttempts:0,cooldownCycle:0,cooldownUntilMs:0,cooldownTimer:null,healthTimer:null})}async*start(e,r){let n=this.sidecars.get(e);return n?(n.state="starting",await this.startFn(n.config.command)?(n.state="running",n.restartAttempts=0,n.cooldownCycle=0,n.cooldownUntilMs=0,yield{type:"voice:sidecar:started",timestamp:Date.now(),sessionId:r,provider:n.config.id,endpoint:n.config.healthEndpoint},this.startHealthLoop(n,r),!0):(yield*this.handleFailure(n,r),n.state==="running")):!1}inFailureCooldown(e){let r=this.sidecars.get(e);return r?r.state==="cooldown"&&Date.now()<r.cooldownUntilMs:!1}cooldownUntil(e){return this.sidecars.get(e)?.cooldownUntilMs??0}async*markFailure(e,r){let n=this.sidecars.get(e);n&&(yield*this.handleFailure(n,r))}async*clearFailure(e,r){let n=this.sidecars.get(e);return n?(n.cooldownTimer&&(clearTimeout(n.cooldownTimer),n.cooldownTimer=null),n.restartAttempts=0,n.cooldownCycle=0,n.cooldownUntilMs=0,yield*this.start(e,r)):!1}activeFallback(e){let r=this.sidecars.get(e);return!r||r.state!=="cooldown"?null:r.config.fallbackProvider??null}getState(e){return this.sidecars.get(e)?.state??null}stop(e){let r=this.sidecars.get(e);r&&(r.cooldownTimer&&(clearTimeout(r.cooldownTimer),r.cooldownTimer=null),r.healthTimer&&(clearTimeout(r.healthTimer),r.healthTimer=null),r.state="stopped")}stopAll(){for(let e of this.sidecars.keys())this.stop(e)}drainEvents(){let e=[...this.pendingEvents];return this.pendingEvents=[],e}async*handleFailure(e,r){let n=e.config.maxRestartAttempts??B.maxRestartAttempts;for(;e.restartAttempts<n;)if(e.restartAttempts++,e.state="restarting",yield{type:"voice:sidecar:crashed",timestamp:Date.now(),sessionId:r,provider:e.config.id,error:`Restart attempt ${e.restartAttempts}/${n}`,restartAttempt:e.restartAttempts},await this.startFn(e.config.command)){e.state="running",e.restartAttempts=0,e.cooldownCycle=0,e.cooldownUntilMs=0,yield{type:"voice:sidecar:started",timestamp:Date.now(),sessionId:r,provider:e.config.id,endpoint:e.config.healthEndpoint},this.startHealthLoop(e,r);return}yield*this.enterCooldown(e,r)}async*enterCooldown(e,r){let n=e.config.baseCooldownMs??B.baseCooldownMs,o=e.config.backoffMultiplier??B.backoffMultiplier,s=e.config.maxCooldownMs??B.maxCooldownMs,i=Math.min(n*Math.pow(o,e.cooldownCycle),s);e.state="cooldown",e.cooldownUntilMs=Date.now()+i,yield{type:"sidecar:cooldown",timestamp:Date.now(),sessionId:r,provider:e.config.id,cooldownUntil:e.cooldownUntilMs,attempts:e.restartAttempts},e.cooldownTimer=setTimeout(()=>{e.cooldownTimer=null,this.probeAfterCooldown(e,r)},i)}async probeAfterCooldown(e,r){if(!await this.healthCheckFn(e.config.healthEndpoint)&&!await this.startFn(e.config.command)){e.cooldownCycle++,e.restartAttempts=0;let s=e.config.baseCooldownMs??B.baseCooldownMs,i=e.config.backoffMultiplier??B.backoffMultiplier,a=e.config.maxCooldownMs??B.maxCooldownMs,c=Math.min(s*Math.pow(i,e.cooldownCycle),a);e.cooldownUntilMs=Date.now()+c,this.pendingEvents.push({type:"sidecar:cooldown",timestamp:Date.now(),sessionId:r,provider:e.config.id,cooldownUntil:e.cooldownUntilMs,attempts:e.restartAttempts}),e.cooldownTimer=setTimeout(()=>{e.cooldownTimer=null,this.probeAfterCooldown(e,r)},c);return}e.state="running",e.restartAttempts=0,e.cooldownCycle=0,e.cooldownUntilMs=0,this.pendingEvents.push({type:"voice:sidecar:started",timestamp:Date.now(),sessionId:r,provider:e.config.id,endpoint:e.config.healthEndpoint}),this.startHealthLoop(e,r)}startHealthLoop(e,r){e.healthTimer&&clearTimeout(e.healthTimer);let n=e.config.healthCheckIntervalMs??B.healthCheckIntervalMs,o=async()=>{if(e.state!=="running")return;if(!await this.healthCheckFn(e.config.healthEndpoint)&&e.state==="running"){e.healthTimer=null,this.pendingEvents.push({type:"voice:sidecar:crashed",timestamp:Date.now(),sessionId:r,provider:e.config.id,error:"Health check failed",restartAttempt:0}),this.probeAfterCooldown(e,r);return}e.state==="running"&&(e.healthTimer=setTimeout(o,n))};e.healthTimer=setTimeout(o,n)}};var le=class{queue=[];playing=null;listener;onEvent(e){this.listener=e}enqueue(e){if(e.interruptMode==="force"){this.forceInterrupt(e);return}if(e.interruptMode==="soft"&&this.playing&&e.priority>this.playing.priority){this.queue.unshift(e),this.emit("speech:queued",e);return}let r=this.queue.findIndex(n=>n.priority<e.priority);r===-1?this.queue.push(e):this.queue.splice(r,0,e),this.emit("speech:queued",e)}forceInterrupt(e){this.playing&&this.emit("speech:interrupted",this.playing),this.playing=e,this.emit("speech:started",e)}interrupt(e){if(this.playing?.id===e)return this.emit("speech:interrupted",this.playing),this.playing=null,this.advance(),!0;let r=this.queue.findIndex(n=>n.id===e);return r>=0?(this.queue.splice(r,1),!0):!1}completeCurrent(){this.playing&&(this.emit("speech:completed",this.playing),this.playing=null),this.advance()}current(){return this.playing}pending(){return[...this.queue]}get size(){return(this.playing?1:0)+this.queue.length}flush(){this.queue.length=0}advance(){if(this.playing)return;let e=this.queue.shift();e&&(this.playing=e,this.emit("speech:started",e))}emit(e,r){this.listener?.(e,r)}};var Cn={happy:{intensity:.7,speed:1.05},sad:{intensity:.6,speed:.9},excited:{intensity:.9,speed:1.15},angry:{intensity:.8,speed:1.1},thoughtful:{intensity:.4,speed:.85},calm:{intensity:.3,speed:.95},nervous:{intensity:.6,speed:1.1},whisper:{intensity:.2,speed:.8}},An=/\[([a-zA-Z][\w-]*)\]([\s\S]*?)\[\/\1\]/g,To=/\[([a-zA-Z][\w-]*)\]/g,bo=/\[\/([a-zA-Z][\w-]*)\]/g;function Tt(t,e=Cn){let r=[],n=0;for(let o of t.matchAll(An)){let s=o.index;if(s>n){let l=t.slice(n,s).trim();l&&r.push({text:l})}let i=o[1],a=o[2].trim(),c=e[i];a&&r.push({text:a,emotion:i,intensity:c?.intensity,speed:c?.speed}),n=s+o[0].length}if(n<t.length){let o=t.slice(n).trim();o&&r.push({text:o})}return r.length===0&&t.trim()&&r.push({text:t.trim()}),r}function bt(t){return t.replace(An,"$2").replace(To,"").replace(bo,"").replace(/\s{2,}/g," ").trim()}function Et(t,e,r=""){let n=[];if(t==null)return n.push(`${r||"root"}: expected ${e.type}, got ${t}`),n;if(e.type==="object"&&typeof t=="object"&&!Array.isArray(t)){let o=t;if(e.required)for(let s of e.required)s in o||n.push(`${r?r+".":""}${s}: required field missing`);if(e.properties)for(let[s,i]of Object.entries(e.properties))s in o&&n.push(...Et(o[s],i,`${r?r+".":""}${s}`))}else if(e.type==="array"&&Array.isArray(t)){if(e.items)for(let o=0;o<t.length;o++)n.push(...Et(t[o],e.items,`${r}[${o}]`))}else e.type==="string"&&typeof t!="string"?n.push(`${r||"root"}: expected string, got ${typeof t}`):e.type==="number"&&typeof t!="number"?n.push(`${r||"root"}: expected number, got ${typeof t}`):e.type==="boolean"&&typeof t!="boolean"&&n.push(`${r||"root"}: expected boolean, got ${typeof t}`);return e.enum&&!e.enum.includes(t)&&n.push(`${r||"root"}: value ${JSON.stringify(t)} not in enum [${e.enum.join(", ")}]`),n}async function kt(t,e,r={}){if(!t.generateObject)throw new Error(`Provider "${t.id}" does not support generateObject`);let n=r.maxRetries??2,o=[],s=0;for(let i=0;i<=n;i++){s++;let a=await t.generateObject(e),c=Et(a,e.schema),l=r.validate?.(a);if(l&&c.push(l),c.length===0)return{data:a,attempts:s,violations:o};o.push(...c.map(d=>`[attempt ${s}] ${d}`)),i<n&&(e={...e,messages:[...e.messages,{role:"assistant",content:JSON.stringify(a)},{role:"user",content:`The previous response had validation errors:
|
|
373
|
+
${c.join(`
|
|
374
|
+
`)}
|
|
375
|
+
|
|
376
|
+
Please fix and return a valid response.`}]})}throw new we(`Structured output validation failed after ${s} attempts`,o)}var we=class extends Error{constructor(r,n){super(r);this.violations=n;this.name="StructuredOutputError"}};var Un="0.1.0";async function _e(t,e={}){let r=new Q,n=new Y,o=e.storage??null;if(!o&&(t.databaseUrl||t.storageBackend)){let{createStorage:S}=await Promise.resolve().then(()=>(At(),$n));o=S({backend:t.storageBackend??"postgres",connectionString:t.databaseUrl})}let s=new q({enableCostTracking:!0});if(t.providers&&Object.keys(t.providers).length>0)for(let[S,$]of Object.entries(t.providers)){let R=Fn($);R&&s.register(S,R)}else{let S=await ne(),$=[S.chat,S.tts,S.stt].filter(R=>R!==null);for(let R of $){let M=Fn({provider:R.id,model:R.id,apiKey:R.apiKeyEnv?process.env[R.apiKeyEnv]:void 0,baseUrl:R.baseUrl});M&&s.register(R.slot,M)}}let i=new oe,a=[Xe,Ke,ze,et,ot,at];for(let S of a)try{S(i)}catch{}try{Qe(i)}catch{}try{Ze(i)}catch{}try{await i.register(ct())}catch{}try{await i.register(ut({skills:[]}))}catch{}let c=new W,l=new J(c),d=t.tools??["*"],u=d.includes("*");e.memoryBackend&&(u||d.includes("memory"))&&c.registerAll(pt(e.memoryBackend)),e.webBackend&&(u||d.includes("web"))&&c.registerAll(mt(e.webBackend)),e.codeBackend&&(u||d.includes("code"))&&c.registerAll(gt(e.codeBackend)),e.fileBackend&&(u||d.includes("files"))&&c.registerAll(ft(e.fileBackend)),e.scheduleBackend&&(u||d.includes("schedule"))&&c.registerAll(yt(e.scheduleBackend)),e.taskBackend&&(u||d.includes("tasks"))&&c.registerAll(ht(e.taskBackend)),e.browserEngine&&(u||d.includes("browser"))&&c.registerAll(vt(e.browserEngine));let f=new ce(async S=>!1,async S=>!1),T=new le,v=null,g;if(t.enablePreClassification){let S=s.getHealthy("utility")??s.getHealthy("chat");S&&(g=Ge(S))}let p=t.systemPrompt??`You are Fenix, an AI agent (${t.edition} edition). You can use tools to help the user.`,m=new Set(t.readOnlyTools??["memory.search","memory.list","memory.context","web.search","web.fetch","files.read","files.list","files.search","tasks.list"]);async function*y(S,$){yield*ae({providers:s,toolRouter:l,extensions:i,sessionId:S,maxTurns:t.maxTurns??20,tokenBudget:t.tokenBudget??128e3,contextWindowTokens:t.contextWindowTokens??2e5,systemPrompt:p,emitBlocks:t.emitBlocks??!1,readOnlyTools:m,classifyQuery:g},$)}function E(){let $=["chat","utility","embedding","vision","stt","tts"].map(M=>({slot:M,healthy:s.getHealthy(M)!==null}));return{status:$.some(M=>M.healthy)?"ok":"degraded",edition:t.edition,version:Un,providers:$,storage:o!==null,extensions:i.listExtensions().length,tools:c.list().length}}async function U(){f.stopAll();for(let S of i.listExtensions())try{await i.unregister(S)}catch{}}return{edition:t.edition,version:Un,config:t,bus:r,sessions:n,providers:s,extensions:i,toolRegistry:c,toolRouter:l,storage:o,voice:{sidecarManager:f,speechQueue:T,parseMarkers:Tt,stripMarkers:bt},memory:{progressiveSearch:v},verifiedGenerateObject:kt,sendMessage:y,health:E,stop:U}}function Fn(t){switch(t.provider){case"anthropic":return new re({apiKey:t.apiKey??process.env.ANTHROPIC_API_KEY??"",model:t.model});case"openrouter":return new L({apiKey:t.apiKey??process.env.OPENROUTER_API_KEY??"",baseUrl:t.baseUrl??"https://openrouter.ai/api/v1",model:t.model,id:`openrouter:${t.model}`});case"ollama":return new L({apiKey:"",baseUrl:t.baseUrl??"http://localhost:11434/v1",model:t.model,id:`ollama:${t.model}`});case"groq":return new L({apiKey:t.apiKey??process.env.GROQ_API_KEY??"",baseUrl:t.baseUrl??"https://api.groq.com/openai/v1",model:t.model,id:`groq:${t.model}`});case"openai":return new L({apiKey:t.apiKey??process.env.OPENAI_API_KEY??"",baseUrl:t.baseUrl??"https://api.openai.com/v1",model:t.model,id:`openai:${t.model}`});case"nvidia":return new L({apiKey:t.apiKey??process.env.NVIDIA_API_KEY??"",baseUrl:t.baseUrl??"https://integrate.api.nvidia.com/v1",model:t.model,id:`nvidia:${t.model}`});case"cloudflare":return new L({apiKey:t.apiKey??process.env.CLOUDFLARE_API_TOKEN??"",baseUrl:t.baseUrl??"https://api.cloudflare.com/client/v4/accounts",model:t.model,id:`cloudflare:${t.model}`});case"github":return new L({apiKey:t.apiKey??process.env.GITHUB_TOKEN??"",baseUrl:t.baseUrl??"https://models.inference.ai.azure.com",model:t.model,id:`github:${t.model}`});default:return t.baseUrl?new L({apiKey:t.apiKey??"",baseUrl:t.baseUrl,model:t.model,id:`${t.provider}:${t.model}`}):null}}var bc=new TextEncoder;At();Re();Ie();var Lo={plan:{filename:"plan.md",template:["# Task Plan","","## Objective","<!-- Describe the current goal -->","","## Checklist","- [ ] Step 1","","## Notes",""].join(`
|
|
377
|
+
`)},observations:{filename:"observations.md",template:["# Observations","","Key observations accumulated this session:","","- ",""].join(`
|
|
378
|
+
`)},context:{filename:"context.md",template:["# Critical Context","","Context that must survive truncation:","","## User Preferences","","## Active Constraints","","## Key Decisions",""].join(`
|
|
379
|
+
`)}};var Rt="0.1.0";function It(t){let e=new Q,r=new Y;return{edition:t.edition,version:Rt,config:t,bus:e,sessions:r}}function D(){return crypto.randomUUID()}function A(){return new Date().toISOString()}function w(t){return t?new Date(t):new Date}function j(t){if(!t)return{};try{return JSON.parse(t)}catch{return{}}}function _t(t){return{id:t.id,conversationId:t.conversation_id,userId:t.user_id,role:t.role,content:t.content,channel:t.channel,tokenCount:t.token_count??null,metadata:j(t.metadata),createdAt:w(t.created_at)}}function Jn(t){return{id:t.id,userId:t.user_id,title:t.title??null,channel:t.channel,metadata:j(t.metadata),createdAt:w(t.created_at),updatedAt:w(t.updated_at)}}function Uo(t){return{id:t.id,userId:t.user_id,content:t.content,category:t.category,embedding:t.embedding?JSON.parse(t.embedding):null,heat:t.heat,accessCount:t.access_count,lastAccessedAt:w(t.last_accessed_at),createdAt:w(t.created_at),updatedAt:w(t.updated_at)}}function Vn(t){return{userId:t.user_id,summary:t.summary,updatedAt:w(t.updated_at)}}function Gn(t){return{id:t.id,userId:t.user_id,conversationId:t.conversation_id??null,content:t.content,category:t.category,reviewed:!!t.reviewed,createdAt:w(t.created_at),reviewedAt:t.reviewed_at?w(t.reviewed_at):null}}function Xn(t){return{id:t.id,conversationId:t.conversation_id,artifactType:t.artifact_type,title:t.title,content:t.content,metadata:j(t.metadata),createdAt:w(t.created_at),updatedAt:w(t.updated_at)}}function Kn(t){return{id:t.id,userId:t.user_id,conversationId:t.conversation_id??null,provider:t.provider,model:t.model,inputTokens:t.input_tokens,outputTokens:t.output_tokens,costUsd:t.cost_usd,createdAt:w(t.created_at)}}function me(t){return{id:t.id,type:t.type,status:t.status,priority:t.priority,payload:j(t.payload),result:t.result?j(t.result):null,error:t.error??null,attempts:t.attempts,maxAttempts:t.max_attempts,claimedAt:t.claimed_at?w(t.claimed_at):null,completedAt:t.completed_at?w(t.completed_at):null,createdAt:w(t.created_at),updatedAt:w(t.updated_at)}}function Pe(t){return{id:t.id,userId:t.user_id,sourceType:t.source_type,uri:t.uri,status:t.status,metadata:j(t.metadata),createdAt:w(t.created_at),updatedAt:w(t.updated_at)}}function Qn(t){return{id:t.id,sourceId:t.source_id,content:t.content,embedding:t.embedding?JSON.parse(t.embedding):null,chunkIndex:t.chunk_index,metadata:j(t.metadata),createdAt:w(t.created_at)}}function Pt(t){return{id:t.id,userId:t.user_id,provider:t.provider,encryptedData:Buffer.from(t.encrypted_data),iv:Buffer.from(t.iv),authTag:Buffer.from(t.auth_tag),createdAt:w(t.created_at),updatedAt:w(t.updated_at)}}function Mt(t){return{id:t.id,workspaceId:t.workspace_id,fileName:t.file_name,content:t.content,metadata:j(t.metadata),createdAt:w(t.created_at),updatedAt:w(t.updated_at)}}var Fo=`
|
|
2
380
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
3
381
|
id TEXT PRIMARY KEY,
|
|
4
382
|
user_id TEXT NOT NULL,
|
|
@@ -144,24 +522,24 @@ CREATE TABLE IF NOT EXISTS cost_events (
|
|
|
144
522
|
metadata TEXT NOT NULL DEFAULT '{}',
|
|
145
523
|
created_at TEXT NOT NULL
|
|
146
524
|
);
|
|
147
|
-
`;function
|
|
148
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[n,
|
|
149
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`,[n,
|
|
150
|
-
VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?, ?)`,[n,
|
|
151
|
-
ON CONFLICT (user_id) DO UPDATE SET summary = excluded.summary, updated_at = excluded.updated_at`,[
|
|
152
|
-
WHERE id IN (${
|
|
153
|
-
VALUES (?, ?, ?, ?, ?, 0, ?)`,[n,
|
|
154
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,[n,
|
|
155
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[n,
|
|
156
|
-
VALUES (?, ?, 'pending', ?, ?, 0, ?, ?, ?)`,[n,
|
|
157
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,[n,
|
|
158
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`,[a,
|
|
525
|
+
`;function G(t){return{async initialize(){t.execSync("PRAGMA journal_mode = WAL;"),t.execSync("PRAGMA foreign_keys = ON;"),t.execSync(Fo)},async close(){},async saveMessage(r){let n=D(),o=A();return t.runSync(`INSERT INTO messages (id, conversation_id, user_id, role, content, channel, token_count, metadata, created_at)
|
|
526
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[n,r.conversationId,r.userId,r.role,r.content,r.channel,r.tokenCount,JSON.stringify(r.metadata),o]),_t(t.getFirstSync("SELECT * FROM messages WHERE id = ?",[n]))},async getMessagesByConversation(r,n=50){return t.getAllSync("SELECT * FROM messages WHERE conversation_id = ? ORDER BY created_at ASC LIMIT ?",[r,n]).map(_t)},async getMessageById(r){let n=t.getFirstSync("SELECT * FROM messages WHERE id = ?",[r]);return n?_t(n):null},async createConversation(r){let n=D(),o=A();return t.runSync(`INSERT INTO conversations (id, user_id, title, channel, metadata, created_at, updated_at)
|
|
527
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,[n,r.userId,r.title,r.channel,JSON.stringify(r.metadata),o,o]),Jn(t.getFirstSync("SELECT * FROM conversations WHERE id = ?",[n]))},async listConversations(r,n){let o=n?.limit??50,s=n?.offset??0;return t.getAllSync("SELECT * FROM conversations WHERE user_id = ? ORDER BY updated_at DESC LIMIT ? OFFSET ?",[r,o,s]).map(Jn)},async deleteConversation(r){t.runSync("DELETE FROM conversations WHERE id = ?",[r])},async saveMemorySegment(r){let n=D(),o=A();return t.runSync(`INSERT INTO memory_segments (id, user_id, content, category, embedding, heat, access_count, last_accessed_at, created_at, updated_at)
|
|
528
|
+
VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?, ?)`,[n,r.userId,r.content,r.category,r.embedding?JSON.stringify(r.embedding):null,r.heat,o,o,o]),Uo(t.getFirstSync("SELECT * FROM memory_segments WHERE id = ?",[n]))},async searchMemoryByEmbedding(r,n,o=10){return[]},async getProfile(r){let n=t.getFirstSync("SELECT * FROM user_profiles WHERE user_id = ?",[r]);return n?Vn(n):null},async upsertProfile(r,n){let o=A();return t.runSync(`INSERT INTO user_profiles (user_id, summary, updated_at) VALUES (?, ?, ?)
|
|
529
|
+
ON CONFLICT (user_id) DO UPDATE SET summary = excluded.summary, updated_at = excluded.updated_at`,[r,n,o]),Vn(t.getFirstSync("SELECT * FROM user_profiles WHERE user_id = ?",[r]))},async updateHeatScores(r,n){if(r.length===0)return;let o=A(),s=r.map(()=>"?").join(",");t.runSync(`UPDATE memory_segments SET heat = heat + ?, access_count = access_count + 1, last_accessed_at = ?
|
|
530
|
+
WHERE id IN (${s})`,[n,o,...r])},async saveObservation(r){let n=D(),o=A();return t.runSync(`INSERT INTO observations (id, user_id, conversation_id, content, category, reviewed, created_at)
|
|
531
|
+
VALUES (?, ?, ?, ?, ?, 0, ?)`,[n,r.userId,r.conversationId,r.content,r.category,o]),Gn(t.getFirstSync("SELECT * FROM observations WHERE id = ?",[n]))},async listPendingObservations(r,n){let o=n?.limit??50,s=n?.offset??0;return t.getAllSync("SELECT * FROM observations WHERE user_id = ? AND reviewed = 0 ORDER BY created_at DESC LIMIT ? OFFSET ?",[r,o,s]).map(Gn)},async markObservationReviewed(r){t.runSync("UPDATE observations SET reviewed = 1, reviewed_at = ? WHERE id = ?",[A(),r])},async saveBrainArtifact(r){let n=D(),o=A();return t.runSync(`INSERT INTO brain_artifacts (id, conversation_id, artifact_type, title, content, metadata, created_at, updated_at)
|
|
532
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,[n,r.conversationId,r.artifactType,r.title,r.content,JSON.stringify(r.metadata),o,o]),Xn(t.getFirstSync("SELECT * FROM brain_artifacts WHERE id = ?",[n]))},async loadBrainArtifacts(r){return t.getAllSync("SELECT * FROM brain_artifacts WHERE conversation_id = ? ORDER BY created_at ASC",[r]).map(Xn)},async deleteBrainArtifact(r){t.runSync("DELETE FROM brain_artifacts WHERE id = ?",[r])},async insertCostLog(r){let n=D(),o=A();return t.runSync(`INSERT INTO cost_logs (id, user_id, conversation_id, provider, model, input_tokens, output_tokens, cost_usd, created_at)
|
|
533
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[n,r.userId,r.conversationId,r.provider,r.model,r.inputTokens,r.outputTokens,r.costUsd,o]),Kn(t.getFirstSync("SELECT * FROM cost_logs WHERE id = ?",[n]))},async queryCostLogs(r){return t.getAllSync("SELECT * FROM cost_logs WHERE user_id = ? AND created_at >= ? AND created_at <= ? ORDER BY created_at DESC",[r.userId,r.startDate.toISOString(),r.endDate.toISOString()]).map(Kn)},async createJob(r){let n=D(),o=A();return t.runSync(`INSERT INTO jobs (id, type, status, priority, payload, attempts, max_attempts, created_at, updated_at)
|
|
534
|
+
VALUES (?, ?, 'pending', ?, ?, 0, ?, ?, ?)`,[n,r.type,r.priority,JSON.stringify(r.payload),r.maxAttempts,o,o]),me(t.getFirstSync("SELECT * FROM jobs WHERE id = ?",[n]))},async claimNextJob(r){let n=r&&r.length>0?`AND type IN (${r.map(()=>"?").join(",")})`:"",o=r&&r.length>0?r:[],s=t.getFirstSync(`SELECT * FROM jobs WHERE status = 'pending' ${n} ORDER BY priority DESC, created_at ASC LIMIT 1`,o);if(!s)return null;let i=A();return t.runSync("UPDATE jobs SET status = 'running', claimed_at = ?, attempts = attempts + 1, updated_at = ? WHERE id = ?",[i,i,s.id]),me(t.getFirstSync("SELECT * FROM jobs WHERE id = ?",[s.id]))},async updateJobStatus(r,n,o,s){let i=A(),a=n==="completed"||n==="failed"||n==="dead"?i:null;return t.runSync("UPDATE jobs SET status = ?, result = ?, error = ?, completed_at = COALESCE(?, completed_at), updated_at = ? WHERE id = ?",[n,o?JSON.stringify(o):null,s??null,a,i,r]),me(t.getFirstSync("SELECT * FROM jobs WHERE id = ?",[r]))},async getJobById(r){let n=t.getFirstSync("SELECT * FROM jobs WHERE id = ?",[r]);return n?me(n):null},async listJobs(r,n){let o=[],s=[];r.status&&(o.push("status = ?"),s.push(r.status)),r.type&&(o.push("type = ?"),s.push(r.type));let i=o.length>0?`WHERE ${o.join(" AND ")}`:"",a=n?.limit??50,c=n?.offset??0;return s.push(a,c),t.getAllSync(`SELECT * FROM jobs ${i} ORDER BY created_at DESC LIMIT ? OFFSET ?`,s).map(me)},async markDeadJobs(r){let n=A(),o=new Date(Date.now()-r*1e3).toISOString(),{changes:s}=t.runSync("UPDATE jobs SET status = 'dead', updated_at = ?, completed_at = ? WHERE status = 'running' AND claimed_at < ?",[n,n,o]);return s},async createContentSource(r){let n=D(),o=A();return t.runSync(`INSERT INTO content_sources (id, user_id, source_type, uri, status, metadata, created_at, updated_at)
|
|
535
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,[n,r.userId,r.sourceType,r.uri,r.status,JSON.stringify(r.metadata),o,o]),Pe(t.getFirstSync("SELECT * FROM content_sources WHERE id = ?",[n]))},async updateContentSourceStatus(r,n){return t.runSync("UPDATE content_sources SET status = ?, updated_at = ? WHERE id = ?",[n,A(),r]),Pe(t.getFirstSync("SELECT * FROM content_sources WHERE id = ?",[r]))},async getContentSourceById(r){let n=t.getFirstSync("SELECT * FROM content_sources WHERE id = ?",[r]);return n?Pe(n):null},async listContentSources(r,n){let o=n?.limit??50,s=n?.offset??0;return t.getAllSync("SELECT * FROM content_sources WHERE user_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?",[r,o,s]).map(Pe)},async bulkInsertContentChunks(r){if(r.length===0)return[];let n=[],o=A();for(let i of r){let a=D();n.push(a),t.runSync(`INSERT INTO content_chunks (id, source_id, content, embedding, chunk_index, metadata, created_at)
|
|
536
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,[a,i.sourceId,i.content,i.embedding?JSON.stringify(i.embedding):null,i.chunkIndex,JSON.stringify(i.metadata),o])}let s=n.map(()=>"?").join(",");return t.getAllSync(`SELECT * FROM content_chunks WHERE id IN (${s}) ORDER BY chunk_index`,n).map(Qn)},async searchContentChunksByEmbedding(r,n,o=10){return[]},async searchContentChunksByText(r,n,o=10){if(r.length===0)return[];let s=r.map(()=>"?").join(",");return t.getAllSync(`SELECT * FROM content_chunks WHERE source_id IN (${s}) AND content LIKE ? LIMIT ?`,[...r,`%${n}%`,o]).map(i=>({chunk:Qn(i),score:1}))},async deleteContentChunksBySource(r){let{changes:n}=t.runSync("DELETE FROM content_chunks WHERE source_id = ?",[r]);return n},async saveCredential(r){let n=D(),o=A();return t.runSync(`INSERT INTO encrypted_credentials (id, user_id, provider, encrypted_data, iv, auth_tag, created_at, updated_at)
|
|
159
537
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
160
538
|
ON CONFLICT (user_id, provider) DO UPDATE
|
|
161
|
-
SET encrypted_data = excluded.encrypted_data, iv = excluded.iv, auth_tag = excluded.auth_tag, updated_at = excluded.updated_at`,[n,
|
|
539
|
+
SET encrypted_data = excluded.encrypted_data, iv = excluded.iv, auth_tag = excluded.auth_tag, updated_at = excluded.updated_at`,[n,r.userId,r.provider,r.encryptedData,r.iv,r.authTag,o,o]),Pt(t.getFirstSync("SELECT * FROM encrypted_credentials WHERE user_id = ? AND provider = ?",[r.userId,r.provider]))},async getCredential(r,n){let o=t.getFirstSync("SELECT * FROM encrypted_credentials WHERE user_id = ? AND provider = ?",[r,n]);return o?Pt(o):null},async deleteCredential(r){t.runSync("DELETE FROM encrypted_credentials WHERE id = ?",[r])},async listCredentials(r){return t.getAllSync("SELECT * FROM encrypted_credentials WHERE user_id = ? ORDER BY provider",[r]).map(Pt)},async saveIdentityFile(r){let n=D(),o=A();return t.runSync(`INSERT INTO identity_files (id, workspace_id, file_name, content, metadata, created_at, updated_at)
|
|
162
540
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
163
541
|
ON CONFLICT (workspace_id, file_name) DO UPDATE
|
|
164
|
-
SET content = excluded.content, metadata = excluded.metadata, updated_at = excluded.updated_at`,[n,
|
|
542
|
+
SET content = excluded.content, metadata = excluded.metadata, updated_at = excluded.updated_at`,[n,r.workspaceId,r.fileName,r.content,JSON.stringify(r.metadata),o,o]),Mt(t.getFirstSync("SELECT * FROM identity_files WHERE workspace_id = ? AND file_name = ?",[r.workspaceId,r.fileName]))},async getIdentityFile(r){let n=t.getFirstSync("SELECT * FROM identity_files WHERE workspace_id = ? ORDER BY created_at DESC LIMIT 1",[r]);return n?Mt(n):null},async listIdentityFiles(){return t.getAllSync("SELECT * FROM identity_files ORDER BY created_at DESC").map(Mt)},async query(r,n){return t.getAllSync(r,n)}}}function Bo(t){let e=0;for(let r of t.messages)typeof r.content=="string"&&(e+=r.content.length);return Math.ceil(e/4)}function Yn(t,e){let r=e.isOnline?.()??!0,n=e.localProvider;return!r&&n?n:t.tools?.length&&n&&!n.capabilities().nativeToolCalling||n&&Bo(t)>n.capabilities().maxContextTokens?e.cloudProvider:e.preferLocal&&n?n:r?e.cloudProvider:n??e.cloudProvider}function ge(t){return{id:"hybrid-router",async complete(e){return Yn(e,t).complete(e)},async*stream(e){let r=Yn(e,t);r.stream&&(yield*r.stream(e))},capabilities(){let e=t.cloudProvider.capabilities(),r=t.localProvider?.capabilities();return{nativeToolCalling:e.nativeToolCalling||(r?.nativeToolCalling??!1),vision:e.vision||(r?.vision??!1),streaming:e.streaming||(r?.streaming??!1),structuredOutput:e.structuredOutput||(r?.structuredOutput??!1),maxContextTokens:Math.max(e.maxContextTokens,r?.maxContextTokens??0)}}}}var Nt="mobile",jo={...Be},zn={edition:Nt,channels:["telegram","web","sms"],tools:["category:llm","category:file","category:memory","category:notification"],layers:["memory"]};function Ho(t){return It({...zn,...t})}async function qo(t){return _e({edition:Nt,storageBackend:"sqlite",tools:["memory","files","tasks"],maxTurns:10,tokenBudget:64e3,...t})}async function fe(t){let e=G(t.db);await e.initialize();let r=ge({cloudProvider:t.cloudProvider,localProvider:t.localProvider,preferLocal:t.preferLocal??!1,isOnline:t.isOnline}),n=new W;n.register({name:"memory.search",description:"Search memory segments",parameters:{query:{type:"string",required:!0}},handler:async c=>({profile:await e.getProfile(String(c.query))})});let o=new J(n),s=new q;s.register("chat",r);let i=crypto.randomUUID(),a={providers:s,toolRouter:o,sessionId:i,maxTurns:t.maxTurns??10,tokenBudget:t.tokenBudget??64e3,systemPrompt:"You are Fenix, a helpful AI assistant running on mobile. Keep responses concise."};return{run(c){return ae(a,c)},storage:e,provider:r,sessionId:i}}var Wo=`
|
|
165
543
|
CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts
|
|
166
544
|
USING fts5(content, category, content=memory_segments, content_rowid=rowid);
|
|
167
545
|
|
|
@@ -187,25 +565,25 @@ BEGIN
|
|
|
187
565
|
INSERT INTO memory_fts(rowid, content, category)
|
|
188
566
|
VALUES (NEW.rowid, NEW.content, NEW.category);
|
|
189
567
|
END;
|
|
190
|
-
`;function
|
|
568
|
+
`;function Jo(t,e){if(t.length!==e.length||t.length===0)return 0;let r=0,n=0,o=0;for(let i=0;i<t.length;i++)r+=t[i]*e[i],n+=t[i]*t[i],o+=e[i]*e[i];let s=Math.sqrt(n)*Math.sqrt(o);return s===0?0:r/s}function Zn(t,e,r){let n=new Map;for(let o=0;o<t.length;o++)n.set(t[o],e*(1/(r+o+1)));return n}function ye(t){let{db:e}=t,r=t.rrfK??60,n=t.ftsWeight??1,o=t.embeddingWeight??1;e.execSync(Wo);function s(a,c=10){let l=e.getAllSync(`SELECT m.id, m.content, m.category, fts.rank
|
|
191
569
|
FROM memory_fts fts
|
|
192
570
|
JOIN memory_segments m ON m.rowid = fts.rowid
|
|
193
571
|
WHERE memory_fts MATCH ?
|
|
194
572
|
ORDER BY fts.rank
|
|
195
|
-
LIMIT ?`,[a,
|
|
573
|
+
LIMIT ?`,[a,c]),d=l.length>0?Math.abs(l[0].rank):1;return l.map(u=>({id:u.id,content:u.content,category:u.category,confidence:d>0?Math.abs(u.rank)/d:0,score:-u.rank}))}async function i(a,c,l=10){let d=s(a,l*2),f=e.getAllSync("SELECT id, content, category, embedding FROM memory_segments WHERE embedding IS NOT NULL").map(m=>({id:m.id,content:m.content,category:m.category,score:Jo(c,JSON.parse(m.embedding))})).sort((m,y)=>y.score-m.score).slice(0,l*2),T=Zn(d.map(m=>m.id),n,r),v=Zn(f.map(m=>m.id),o,r),g=new Map;for(let m of d)g.set(m.id,{content:m.content,category:m.category});for(let m of f)g.has(m.id)||g.set(m.id,{content:m.content,category:m.category});let p=[];for(let[m,y]of g){let E=(T.get(m)??0)+(v.get(m)??0),U=n*(1/(r+1))+o*(1/(r+1));p.push({id:m,content:y.content,category:y.category,confidence:U>0?E/U:0,score:E})}return p.sort((m,y)=>y.score-m.score),p.slice(0,l)}return{searchFTS:s,searchHybrid:i}}function Vo(t){return{name:"device.calendar",description:"Read and create calendar events on this device",parameters:{action:{type:"string",description:"list | create | search",required:!0},startDate:{type:"string",description:"ISO date for query range start"},endDate:{type:"string",description:"ISO date for query range end"},title:{type:"string",description:"Event title (for create)"},location:{type:"string",description:"Event location (for create)"},query:{type:"string",description:"Search query"}},handler:async e=>{let{status:r}=await t.requestPermissions();if(r!=="granted")return{error:"Calendar permission denied"};let n=String(e.action);if(n==="list"){let o=e.startDate?new Date(String(e.startDate)):new Date,s=e.endDate?new Date(String(e.endDate)):new Date(o.getTime()+7*864e5),a=(await t.getCalendarsAsync()).map(l=>l.id);return{events:(await t.getEventsAsync(a,o,s)).map(er)}}if(n==="create"){let o=await t.getCalendarsAsync();return o.length===0?{error:"No calendars available"}:{created:!0,eventId:await t.createEventAsync(o[0].id,{title:String(e.title??"Untitled"),startDate:e.startDate?new Date(String(e.startDate)):new Date,endDate:e.endDate?new Date(String(e.endDate)):new Date(Date.now()+36e5),location:e.location?String(e.location):void 0})}}if(n==="search"){let o=new Date(Date.now()-2592e6),s=new Date(Date.now()+90*864e5),a=(await t.getCalendarsAsync()).map(u=>u.id),c=await t.getEventsAsync(a,o,s),l=String(e.query??"").toLowerCase();return{events:c.filter(u=>u.title.toLowerCase().includes(l)||u.notes?.toLowerCase().includes(l)).map(er)}}return{error:`Unknown action: ${n}`}}}}function er(t){return{id:t.id,title:t.title,start:t.startDate,end:t.endDate,location:t.location}}function Go(t){return{name:"device.contacts",description:"Search and read contacts on this device",parameters:{action:{type:"string",description:"search | list",required:!0},query:{type:"string",description:"Name to search for"},limit:{type:"number",description:"Max results (default 10)"}},handler:async e=>{let{status:r}=await t.requestPermissions();if(r!=="granted")return{error:"Contacts permission denied"};let n=String(e.action),o=Number(e.limit)||10,{data:s}=await t.getContactsAsync({fields:["phoneNumbers","emails"],pageSize:200});if(n==="list")return{contacts:s.slice(0,o).map(tr)};if(n==="search"){let i=String(e.query??"").toLowerCase();return{contacts:s.filter(c=>(c.name??`${c.firstName??""} ${c.lastName??""}`).toLowerCase().includes(i)).slice(0,o).map(tr)}}return{error:`Unknown action: ${n}`}}}}function tr(t){return{id:t.id,name:t.name??`${t.firstName??""} ${t.lastName??""}`.trim(),phone:t.phoneNumbers?.[0]?.number??null,email:t.emails?.[0]?.email??null}}function Xo(t){return{name:"device.camera",description:"Capture a photo or pick from gallery",parameters:{action:{type:"string",description:"capture | pick",required:!0}},handler:async e=>{let r=String(e.action);if(r==="capture"){let{status:n}=await t.requestCameraPermissions();if(n!=="granted")return{error:"Camera permission denied"};let o=await t.takePicture();return{uri:o.uri,width:o.width,height:o.height}}if(r==="pick"){let n=await t.pickImage();return n?{uri:n.uri,width:n.width,height:n.height}:{error:"No image selected"}}return{error:`Unknown action: ${r}`}}}}function Ko(t){return{name:"device.location",description:"Get current location or reverse geocode coordinates",parameters:{action:{type:"string",description:"current | geocode",required:!0},latitude:{type:"number",description:"Latitude (for geocode)"},longitude:{type:"number",description:"Longitude (for geocode)"}},handler:async e=>{let{status:r}=await t.requestForegroundPermissions();if(r!=="granted")return{error:"Location permission denied"};let n=String(e.action);if(n==="current"){let o=await t.getCurrentPosition(),[s]=await t.reverseGeocode(o.coords.latitude,o.coords.longitude);return{latitude:o.coords.latitude,longitude:o.coords.longitude,altitude:o.coords.altitude,address:s?`${s.street??""}, ${s.city??""}, ${s.region??""}, ${s.country??""}`.replace(/^, |, $/g,""):null}}if(n==="geocode"){let o=Number(e.latitude),s=Number(e.longitude);if(isNaN(o)||isNaN(s))return{error:"Invalid coordinates"};let[i]=await t.reverseGeocode(o,s);return i??{error:"No results"}}return{error:`Unknown action: ${n}`}}}}function Qo(t){return{name:"device.reminders",description:"Read and create reminders on this device (iOS)",parameters:{action:{type:"string",description:"list | create",required:!0},title:{type:"string",description:"Reminder title (for create)"},dueDate:{type:"string",description:"ISO due date (for create)"},notes:{type:"string",description:"Notes (for create)"}},handler:async e=>{let{status:r}=await t.requestRemindersPermissions();if(r!=="granted")return{error:"Reminders permission denied"};let n=String(e.action),o=await t.getCalendarsAsync("reminder");if(o.length===0)return{error:"No reminder calendars available"};let s=o.map(i=>i.id);return n==="list"?{reminders:(await t.getRemindersAsync(s)).map(a=>({id:a.id,title:a.title,dueDate:a.dueDate??null,completed:a.completed}))}:n==="create"?{created:!0,reminderId:await t.createReminderAsync(s[0],{title:String(e.title??"Untitled reminder"),dueDate:e.dueDate?new Date(String(e.dueDate)):void 0,notes:e.notes?String(e.notes):void 0})}:{error:`Unknown action: ${n}`}}}}function Yo(t){return{name:"device.notifications",description:"Schedule, list, and cancel local notifications",parameters:{action:{type:"string",description:"schedule | list | cancel",required:!0},title:{type:"string",description:"Notification title (for schedule)"},body:{type:"string",description:"Notification body (for schedule)"},delaySeconds:{type:"number",description:"Delay in seconds (for schedule, default immediate)"},notificationId:{type:"string",description:"Notification ID (for cancel)"}},handler:async e=>{let{status:r}=await t.requestPermissions();if(r!=="granted")return{error:"Notification permission denied"};let n=String(e.action);if(n==="schedule"){let o=Number(e.delaySeconds)||0;return{scheduled:!0,notificationId:await t.scheduleNotification({title:String(e.title??"Fenix"),body:String(e.body??"")},o>0?{seconds:o}:null)}}return n==="list"?{notifications:(await t.getPendingNotifications()).map(s=>({id:s.identifier,title:s.content.title,body:s.content.body}))}:n==="cancel"?e.notificationId?(await t.cancelNotification(String(e.notificationId)),{cancelled:!0}):{error:"notificationId required"}:{error:`Unknown action: ${n}`}}}}var Me=new Set(["shell","code_execute","browser","mcp_server"]);function Lt(t){let e=t.tools.filter(s=>!Me.has(s.name));function r(){return t.isOnline?.()??!0?e:e.filter(i=>!i.requiresNetwork)}function n(s){if(Me.has(s))return;let i=e.find(a=>a.name===s);if(i&&!(i.requiresNetwork&&!(t.isOnline?.()??!0)))return i}function o(s){return Me.has(s)}return{listAvailable:r,get:n,isExcluded:o,EXCLUDED:[...Me]}}var zo="default",Zo={"soul.md":["# Soul","You are Fenix, a helpful AI assistant.","You are thoughtful, concise, and respectful."].join(`
|
|
196
574
|
`),"persona.md":["# Persona","Friendly and professional. Adapt to the user's communication style."].join(`
|
|
197
575
|
`),"user.md":["# User","No user profile yet. Learn about the user through conversation."].join(`
|
|
198
576
|
`),"knowledge.md":["# Knowledge","No domain knowledge loaded yet."].join(`
|
|
199
|
-
`)};function
|
|
200
|
-
VALUES (?, ?, ?, ?, '{}', ?, ?)`,[
|
|
201
|
-
VALUES (?, ?, ?, ?, '{}', ?, ?)`,[a,
|
|
577
|
+
`)};function he(t,e=zo){function r(){for(let[n,o]of Object.entries(Zo))if(!t.getFirstSync("SELECT id FROM identity_files WHERE workspace_id = ? AND file_name = ?",[e,n])){let i=crypto.randomUUID(),a=new Date().toISOString();t.runSync(`INSERT INTO identity_files (id, workspace_id, file_name, content, metadata, created_at, updated_at)
|
|
578
|
+
VALUES (?, ?, ?, ?, '{}', ?, ?)`,[i,e,n,o,a,a])}}return r(),{async read(n){return t.getFirstSync("SELECT content FROM identity_files WHERE workspace_id = ? AND file_name = ?",[e,n])?.content??null},async write(n,o){let s=new Date().toISOString();if(t.getFirstSync("SELECT id FROM identity_files WHERE workspace_id = ? AND file_name = ?",[e,n]))t.runSync("UPDATE identity_files SET content = ?, updated_at = ? WHERE workspace_id = ? AND file_name = ?",[o,s,e,n]);else{let a=crypto.randomUUID();t.runSync(`INSERT INTO identity_files (id, workspace_id, file_name, content, metadata, created_at, updated_at)
|
|
579
|
+
VALUES (?, ?, ?, ?, '{}', ?, ?)`,[a,e,n,o,s,s])}},async list(){return t.getAllSync("SELECT file_name FROM identity_files WHERE workspace_id = ? ORDER BY file_name",[e]).map(o=>o.file_name)},async getVersion(n){let o=t.getFirstSync("SELECT updated_at FROM identity_files WHERE workspace_id = ? AND file_name = ?",[e,n]);return o?new Date(o.updated_at).getTime():0}}}async function es(t){let e=t.userId??"default",r=G(t.db);await r.initialize();let n=ye({db:t.db}),o=he(t.db),s=await fe({db:t.db,cloudProvider:t.cloudProvider,localProvider:t.localProvider,preferLocal:t.preferLocal,isOnline:t.isOnline});return{db:t.db,storage:r,identityStore:o,memorySearch:n,agent:s,userId:e,syncEnabled:!1,syncPending:!1,lastSyncTime:null,isOnline:t.isOnline??(()=>!0)}}function ts(t,e,r){let n=!1;return{id:`embedded:${t.split("/").pop()??"local"}`,async complete(o){if(!r)throw new Error("Embedded inference engine not available. Install react-native-llama.");n||(await r.load(t,e),n=!0);let s=o.messages.map(a=>a.role==="system"?`<|system|>
|
|
202
580
|
${a.content}
|
|
203
581
|
`:a.role==="user"?`<|user|>
|
|
204
582
|
${a.content}
|
|
205
583
|
`:`<|assistant|>
|
|
206
584
|
${a.content}
|
|
207
585
|
`).join("")+`<|assistant|>
|
|
208
|
-
`,
|
|
586
|
+
`,i=await r.complete(s,o.maxTokens??512,o.temperature??.7);return{content:i,finishReason:"stop",usage:{inputTokens:Math.ceil(s.length/4),outputTokens:Math.ceil(i.length/4)}}},capabilities(){return{nativeToolCalling:!1,vision:!1,streaming:!1,structuredOutput:!1,maxContextTokens:e}}}}function ns(t,e,r=globalThis.fetch){let n=t.replace(/\/$/,"");return{id:`ollama:${e}`,async complete(o){let s=o.messages.map(c=>({role:c.role,content:c.content??""})),i=await r(`${n}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:e,messages:s,stream:!1,options:{temperature:o.temperature??.7,num_predict:o.maxTokens??512}})});if(!i.ok)throw new Error(`Ollama error: ${i.status} ${i.statusText}`);let a=await i.json();return{content:a.message.content,finishReason:"stop",usage:{inputTokens:a.prompt_eval_count??0,outputTokens:a.eval_count??0}}},capabilities(){return{nativeToolCalling:!1,vision:!1,streaming:!0,structuredOutput:!1,maxContextTokens:4096}}}}function Ot(t){return t.type==="embedded"?ts(t.modelPath??"",t.contextSize??2048):ns(t.ollamaUrl??"http://localhost:11434",t.model??"qwen3.5:2b",t.fetchFn)}var rs=`
|
|
209
587
|
CREATE TABLE IF NOT EXISTS sync_state (
|
|
210
588
|
key TEXT PRIMARY KEY,
|
|
211
589
|
value TEXT NOT NULL
|
|
@@ -222,9 +600,9 @@ CREATE TABLE IF NOT EXISTS sync_conflicts (
|
|
|
222
600
|
resolved_to TEXT NOT NULL,
|
|
223
601
|
created_at TEXT NOT NULL
|
|
224
602
|
);
|
|
225
|
-
`;function
|
|
226
|
-
ON CONFLICT (key) DO UPDATE SET value = excluded.value`,[
|
|
227
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[y,
|
|
228
|
-
VALUES (?, 'default', ?, ?, ?, 0, ?, ?, ?)`,[
|
|
229
|
-
VALUES (?, ?, 'default', ?, ?, 'sync', '{}', ?)`,[
|
|
230
|
-
VALUES (?, 'default', ?, ?, '{}', ?, ?)`,[y,u.fileName,u.content,u.updatedAt,u.updatedAt])}}}return{async status(){return(await M(`${s}/sync/status`,{method:"GET",headers:a},o,i)).json()},async push(m){let p=await(await M(`${s}/sync/push`,{method:"POST",headers:a,body:JSON.stringify(m)},o,i)).json();if(p.conflicts.length>0)for(let y of p.conflicts)c(y,null,null);return p},async pull(m){let p=await(await M(`${s}/sync/pull?since=${encodeURIComponent(m)}`,{method:"GET",headers:a},o,i)).json();return f(p.facts),_(p.messages),E(p.identity),p},async ack(m){await M(`${s}/sync/ack`,{method:"POST",headers:a,body:JSON.stringify({receivedUpTo:m})},o,i),g("last_sync",m)},async fullSync(){let m=l("last_sync")??"1970-01-01T00:00:00.000Z",u=d(m),p=await this.push(u),y=await this.pull(m),O=y.serverTime??p.serverTime??new Date().toISOString();return await this.ack(O),{pushed:p,pulled:y}}}}var G="fenix-background-sync";function j(e){let{syncClient:r,isOnline:t,onSyncStart:n,onSyncEnd:o,registerBackgroundTask:i,unregisterBackgroundTask:s}=e,a=e.debounceMs??3e5,l=e.backgroundIntervalMs??18e5,g=null,c=!1;async function d(f){if(!t())return{success:!1,source:f,error:"offline"};if(c)return{success:!1,source:f,error:"sync_in_progress"};if(n?.(f)===!1)return{success:!1,source:f,error:"cancelled"};c=!0;try{let{pushed:E,pulled:m}=await r.fullSync(),u={success:!0,source:f,pushed:E.accepted,pulled:m.facts.length+m.messages.length+m.identity.length};return o?.(f,u),u}catch(E){let m={success:!1,source:f,error:E instanceof Error?E.message:String(E)};return o?.(f,m),m}finally{c=!1}}return{async onForeground(){return d("foreground")},onConversationIdle(){g&&clearTimeout(g),g=setTimeout(()=>{g=null,d("post_conversation")},a)},async syncNow(){return d("manual")},async onPushNotification(){return d("push")},async registerBackground(){i&&await i(G,l)},async unregisterBackground(){s&&await s(G)},executeSync:d,dispose(){g&&(clearTimeout(g),g=null)}}}async function R(e){let r=e.userId??"default",t=e.isOnline??(()=>!0),n=v(e.db);await n.initialize();let o=N({db:e.db}),i=x(e.db),s=e.localModel?H(e.localModel):void 0,a=A({cloudProvider:e.cloudProvider,localProvider:s,preferLocal:e.preferLocal??!1,isOnline:t}),l=V({tools:e.tools??[],isOnline:t}),g=await L({db:e.db,cloudProvider:e.cloudProvider,localProvider:s,preferLocal:e.preferLocal,isOnline:t}),c=null,d=null,f=!!e.sync;return e.sync&&(c=W({serverUrl:e.sync.serverUrl,authToken:e.sync.authToken,db:e.db}),d=j({syncClient:c,isOnline:t,registerBackgroundTask:e.registerBackgroundTask,unregisterBackgroundTask:e.unregisterBackgroundTask}),await d.registerBackground(),d.onForeground()),{db:e.db,storage:n,identityStore:i,memorySearch:o,agent:g,userId:r,syncEnabled:f,syncPending:!1,lastSyncTime:null,isOnline:t,syncClient:c,syncTriggers:d,toolRegistry:l,dispose(){d?.dispose()}}}function et(e){let{onMessage:r,connectivity:t}=e,n=[],o=!1;async function i(l){let g={type:l.type??"text_input",payload:String(l.payload??""),timestamp:String(l.timestamp??new Date().toISOString())};if(g.payload.trim()){await s("thinking"),o=!0;try{let{response:c,suggestions:d}=await r(g.payload);t.isReachable()?await t.sendMessage({type:"response",payload:w(c),suggestions:d.slice(0,3)}):t.transferUserInfo({type:"response",payload:w(c),suggestions:d.slice(0,3)})}catch(c){let d=c instanceof Error?c.message:"Something went wrong";t.isReachable()&&await t.sendMessage({type:"error",payload:w(d)})}finally{o=!1,await s("idle")}}}async function s(l){try{t.isReachable()&&await t.sendMessage({type:"status",status:l})}catch{}}async function a(l,g){let c={type:"response",payload:w(l)};g?.length&&(c.suggestions=g.slice(0,3)),t.isReachable()?await t.sendMessage(c):t.transferUserInfo(c)}return{start(){return t.onMessage(i)},sendStatus:s,sendResponse:a,isWatchReachable(){return t.isReachable()},getPendingQueue(){return[...n]}}}function w(e,r=500){return e.length<=r?e:e.slice(0,r-3)+"..."}function tt(e){let r=[];return e.includes("?")&&r.push("Yes","No"),e.toLowerCase().includes("remind")&&r.push("Set reminder"),(e.toLowerCase().includes("meeting")||e.toLowerCase().includes("calendar"))&&r.push("Show calendar"),r.length===0&&r.push("Tell me more","Thanks"),r.slice(0,3)}var nt={trigger:"send_message",grip:"push_to_talk",thumbstick_click:"cancel"};function Q(e={}){let r={...nt,...e.mapping},t=e.voiceCapture;return{handleControllerEvent(n){if(!n.pressed)return null;let o=null;switch(n.button){case"trigger":o=r.trigger==="none"?null:r.trigger;break;case"grip":o=r.grip==="none"?null:r.grip;break;case"thumbstick_click":o=r.thumbstick_click==="none"?null:r.thumbstick_click;break;default:o=null}return o&&e.onAction?.(o,n),o},async startVoice(){if(!t)throw new Error("Voice capture not available on this device");await t.startRecording()},async stopVoice(){return!t||!t.isRecording()?null:t.stopRecording()},isRecordingVoice(){return t?.isRecording()??!1},getMapping(){return{...r}},setMapping(n){Object.assign(r,n)}}}var D={width:1024,height:768,backgroundOpacity:.95,fontScale:1.2,minTouchTarget:48,showSystemKeyboard:!0};function q(e=D){return{baseFontSize:Math.round(16*e.fontScale),headingFontSize:Math.round(24*e.fontScale),minTouchTarget:e.minTouchTarget,panelWidth:e.width,panelHeight:e.height,backgroundOpacity:e.backgroundOpacity}}async function rt(e){let r=await R(e),t={...D,...e.panel},n=q(t),o=Q(e.controller);return{fenix:r,controller:o,styles:n,panel:t,dispose(){r.dispose()}}}function Y(e){let{onTranscription:r,wakeWordDetector:t}=e,n=e.isOnline??(()=>!0),o=!1,i=!1;function s(){return!n()&&e.offlineSTT?e.offlineSTT:e.sttProvider}function a(){return!n()&&e.offlineTTS?e.offlineTTS:e.ttsProvider}async function l(){if(o)return"";o=!0;try{let c=await s().stopListening();if(!c.trim())return"";let d=await r(c);return d&&await a().speak(d),d}finally{o=!1}}return{start(){i=!0,t?.start(async()=>{o||await s().startListening(()=>{})})},stop(){i=!1,t?.stop(),a().stop()},async pushToTalk(){return await s().startListening(()=>{}),l()},async speak(g){await a().speak(g)},isBusy(){return o}}}function $(e){let{camera:r}=e,t=e.isOnline??(()=>!0);function n(){return!t()&&e.offlineVisionProvider?e.offlineVisionProvider:e.visionProvider}return{async describeView(o){if(!r.hasPermission()&&!await r.requestPermission())return"Camera permission not granted.";let i=await r.captureFrame("main");return n().describe(i,o??"Describe what you see in this image.")},async captureFrame(){return r.hasPermission()||await r.requestPermission(),r.captureFrame("main")},isAvailable(){return r.hasPermission()}}}var K={touchpad:{tap:"send_message",double_tap:"pin_card",long_press:"activate_agent",swipe_up:"scroll_up",swipe_down:"scroll_down",swipe_left:"dismiss",swipe_right:"none"},head:{nod:"confirm",shake:"deny",tilt_left:"none",tilt_right:"dismiss"},button:{camera_short:"none",camera_long:"activate_agent"}};function z(e={}){let r={touchpad:{...K.touchpad,...e.mapping?.touchpad},head:{...K.head,...e.mapping?.head},button:{...K.button,...e.mapping?.button}};return{handleEvent(t){let n="none";switch(t.source){case"touchpad":n=r.touchpad[t.gesture]??"none";break;case"head":n=r.head[t.gesture]??"none";break;case"button":n=r.button[t.gesture]??"none";break}return n!=="none"&&e.onAction?.(n,t),n},getMapping(){return{touchpad:{...r.touchpad},head:{...r.head},button:{...r.button}}},setMapping(t){t.touchpad&&Object.assign(r.touchpad,t.touchpad),t.head&&Object.assign(r.head,t.head),t.button&&Object.assign(r.button,t.button)}}}function J(e){let r=new Map,t=e.allowedApps?new Set(e.allowedApps):null;return{async handleNotification(n){t&&!t.has(n.app)||(r.set(n.id,n),n.priority==="urgent"&&e.onSpeak&&await e.onSpeak(`Urgent from ${n.app}: ${n.title}. ${n.body}`),e.onDisplay?.(n))},getUnread(){return Array.from(r.values()).sort((n,o)=>new Date(o.timestamp).getTime()-new Date(n.timestamp).getTime())},markRead(n){r.delete(n)},clearAll(){r.clear()},async speakSummary(){let n=Array.from(r.values());if(n.length===0){await e.onSpeak?.("No new notifications.");return}let o;if(e.summarize)o=await e.summarize(n);else if(n.length===1){let i=n[0];o=`You have one notification from ${i.app}: ${i.title}`}else{let i=[...new Set(n.map(s=>s.app))];o=`You have ${n.length} notifications from ${i.join(", ")}`}await e.onSpeak?.(o)}}}function Z(e){let r=!1,t=Y({...e.voice,onTranscription:async a=>{if(["looking at","see","what is this","what's this","describe"].some(c=>a.toLowerCase().includes(c))&&n.isAvailable()){let c=await n.captureFrame();return e.processQuery(a,c.data)}return e.processQuery(a)}}),n=$(e.context),o=z({...e.gesture,onAction:(a,l)=>{s(a),e.gesture?.onAction?.(a,l)}}),i=J({...e.notification,onSpeak:async a=>{await t.speak(a),e.notification?.onSpeak?.(a)}});function s(a){switch(a){case"activate_agent":t.isBusy()||t.pushToTalk();break;case"dismiss":break;case"confirm":case"deny":break}}return{start(){r=!0,t.start()},stop(){r=!1,t.stop()},isRunning(){return r},voice:t,context:n,gesture:o,notification:i}}async function ot(e){let r=await R(e),t=Z({voice:e.voice,context:e.context,gesture:e.gesture,notification:e.notification,async processQuery(n,o){let i="",s=r.agent.run({text:n});for await(let a of s)a&&typeof a=="object"&&a.type==="token"&&(i+=a.token??"");return i||"I couldn't process that. Try again."}});return t.start(),{fenix:r,xr:t,dispose(){t.stop(),r.dispose()}}}function k(e,r,t={}){let n=t.maxBodyLength??120,o=r.length>n?r.slice(0,n-3)+"...":r;return{id:crypto.randomUUID(),title:e.slice(0,40),body:o,timestamp:new Date().toISOString(),pinned:!1,autoDismissMs:t.autoDismissMs??8e3}}function it(e){return{...e,pinned:!0,autoDismissMs:0}}function st(e){return{...e,pinned:!1,autoDismissMs:8e3}}function ee(e,r,t="low"){return{id:crypto.randomUUID(),app:e,text:r.slice(0,60),priority:t,timestamp:new Date().toISOString(),autoDismissMs:t==="high"?6e3:4e3}}function te(e=8){return{messages:[],visible:!1,scrollOffset:0,maxVisibleMessages:e}}function ne(e,r,t){let n={id:crypto.randomUUID(),role:r,content:t,timestamp:new Date().toISOString()},o=[...e.messages,n],i=Math.max(0,o.length-e.maxVisibleMessages);return{...e,messages:o,scrollOffset:i,visible:!0}}function at(e,r){let t=r==="up"?-1:1,n=Math.max(0,e.messages.length-e.maxVisibleMessages),o=Math.max(0,Math.min(n,e.scrollOffset+t));return{...e,scrollOffset:o}}function ct(e){return e.messages.slice(e.scrollOffset,e.scrollOffset+e.maxVisibleMessages)}function re(e=3){return{annotations:[],visible:!1,maxAnnotations:e}}function oe(e,r){let t=r.sort((n,o)=>o.confidence-n.confidence).slice(0,e.maxAnnotations).map(n=>({id:n.id,content:n.content.length>80?n.content.slice(0,77)+"...":n.content,relevance:n.confidence,timestamp:new Date().toISOString()}));return{...e,annotations:t,visible:t.length>0}}function ie(e){return{...e,visible:!1,annotations:[]}}function dt(e){return e.split(/\s+/).filter(Boolean).length}function lt(e,r){let t=e.split(/\s+/).filter(Boolean);return t.length<=r?e:t.slice(0,r).join(" ")+"..."}function ut(e){let{displayType:r,compressResponse:t,onSpeak:n}=e,o=e.monocularWordBudget??50,i=e.binocularWordBudget??150,s={currentCard:null,notifications:[],conversation:te(),memory:re()};async function a(l){let g=r==="monocular"?o:i;return dt(l)<=g?l:t?t(l,g):lt(l,g)}return{async showResponse(l,g){if(r==="none"){await n?.(l);return}let c=await a(l);r==="monocular"?s.currentCard=k("Fenix",c):(s.conversation=ne(s.conversation,"assistant",c),s.currentCard=k("Fenix",c))},showNotification(l,g,c){if(r==="none"){n?.(`${l}: ${g}`);return}let d=ee(l,g,c);s.notifications=[...s.notifications,d]},showMemoryContext(l){r!=="none"&&(s.memory=oe(s.memory,l))},dismiss(){s.currentCard=null,s.notifications=[],s.memory=ie(s.memory)},getDisplayType(){return r},getState(){return{...s}}}}function se(e){let{agent:r,identityStore:t,memorySearch:n,onResponse:o}=e,i=new Map;function s(c,d,f){o({id:c,type:d,payload:f})}async function a(c){let d=new AbortController;i.set(c.id,d);try{let f=c.payload.text,_="",E=r.run({text:f});for await(let m of E){if(d.signal.aborted)return;if(m&&typeof m=="object"&&m.type==="token"){let u=m.token??"";_+=u,s(c.id,"stream_token",{token:u})}}s(c.id,"stream_end",{response:_})}catch(f){d.signal.aborted||s(c.id,"error",{message:f.message??"Agent error"})}finally{i.delete(c.id)}}async function l(c){try{let d=c.payload.query,f=c.payload.limit??10,_=n.searchFTS(d,f);s(c.id,"result",{results:_})}catch(d){s(c.id,"error",{message:d.message??"Search error"})}}async function g(c){try{if(c.type==="identity_read"){let d=c.payload.file,f=t.read(d);s(c.id,"result",{file:d,content:f})}else{let d=c.payload.file,f=c.payload.content;t.write(d,f),s(c.id,"result",{file:d,written:!0})}}catch(d){s(c.id,"error",{message:d.message??"Identity error"})}}return{async handleRequest(c){switch(c.type){case"query":return a(c);case"cancel":let d=c.payload.requestId;i.get(d)?.abort(),i.delete(d),s(c.id,"result",{cancelled:d});return;case"memory_search":return l(c);case"identity_read":case"identity_write":return g(c);case"status":s(c.id,"result",{activeRequests:[...i.keys()],agentReady:!0});return}},cancelRequest(c){i.get(c)?.abort(),i.delete(c)},getActiveRequests(){return[...i.keys()]},dispose(){for(let c of i.values())c.abort();i.clear()}}}function ae(e){let{stt:r,tts:t,onTranscription:n}=e;return{async startListening(){t.isSpeaking()&&t.stop(),await r.startListening()},async stopAndProcess(){let o=await r.stopListening();if(!o.trim())return"";let i=await n(o);return await t.speak(i),i},async speak(o){await t.speak(o)},cancelSpeech(){t.stop()},isListening(){return r.isListening()},isSpeaking(){return t.isSpeaking()}}}function ve(e){return{name:"scene_understanding",description:"Identify objects and surfaces in the user's physical environment using ARKit scene understanding.",parameters:{},async handler(){let r=await e.getSceneObjects();return{objects:r.map(t=>({label:t.label,confidence:Math.round(t.confidence*100),position:`(${t.boundingBox.x.toFixed(1)}, ${t.boundingBox.y.toFixed(1)}, ${t.boundingBox.z.toFixed(1)})`})),count:r.length}}}}function Re(e){return{name:"spatial_anchor",description:"Place or retrieve spatial anchors in the user's environment. Anchors persist across sessions.",parameters:{action:{type:"string",description:"place | list | remove"},label:{type:"string",description:"Label for the anchor (place only)"},position:{type:"object",description:"{ x, y, z } coordinates (place only)"},id:{type:"string",description:"Anchor ID (remove only)"}},async handler(r){let t=r.action;return t==="list"?{anchors:await e.getAnchors()}:t==="place"?{placed:await e.placeAnchor(r.label,r.position)}:t==="remove"?{removed:await e.removeAnchor(r.id)}:{error:"Unknown action. Use place, list, or remove."}}}}function be(e){return{name:"hand_tracking",description:"Read current hand poses and gestures via ARKit hand tracking.",parameters:{},async handler(){return{hands:(await e.getHandPoses()).map(t=>({hand:t.hand,gesture:t.gesture,confidence:Math.round(t.confidence*100)}))}}}}function Ae(e){return{name:"shareplay",description:"Start or end a SharePlay session for collaborative spatial experiences.",parameters:{action:{type:"string",description:"start | end"},sessionId:{type:"string",description:"Session identifier (start only)"}},async handler(r){return r.action==="start"?e.startSharePlay?{started:await e.startSharePlay(r.sessionId)}:{error:"SharePlay not available"}:r.action==="end"?e.endSharePlay?(await e.endSharePlay(),{ended:!0}):{error:"SharePlay not available"}:{error:"Unknown action. Use start or end."}}}}function ce(e){return[ve(e),Re(e),be(e),Ae(e)]}async function pt(e){let r=e.tools??[];e.nativeAPIs&&r.push(...ce(e.nativeAPIs));let t=await R({...e,tools:r}),n=se({agent:t.agent,identityStore:t.identityStore,memorySearch:t.memorySearch,onResponse:e.onBridgeResponse??(()=>{})}),o=null;return e.voice&&(o=ae(e.voice)),{fenix:t,bridge:n,voice:o,mode:e.mode,dispose(){n.dispose(),t.dispose()}}}export{D as DEFAULT_PANEL_CONFIG,X as EDITION,Oe as KERNEL_VERSION,Ee as MOBILE_KERNEL_CONFIG,ke as MOBILE_MANIFEST,G as SYNC_TASK_NAME,ne as appendMessage,$e as bootApp,Se as bootKernel,Fe as bootMobile,se as createAgentBridge,Ve as createCalendarTool,We as createCameraTool,He as createContactsTool,$ as createContextCapture,te as createConversationOverlay,ut as createDisplayManager,z as createGestureHandler,k as createGlanceCard,be as createHandTrackingTool,A as createHybridRouter,x as createIdentityStore,Te as createKernel,H as createLocalProvider,Ge as createLocationTool,re as createMemoryHUD,N as createMemorySearch,L as createMobileAgent,V as createMobileToolRegistry,J as createNotificationBridge,ee as createNotificationPill,Qe as createNotificationsTool,Q as createQuestAdapter,je as createRemindersTool,v as createSQLiteAdapter,ve as createSceneUnderstandingTool,Ae as createSharePlayTool,Re as createSpatialAnchorTool,W as createSyncClient,j as createSyncTriggers,ce as createVisionOSTools,ae as createVisionVoiceInterface,Y as createVoiceInterface,et as createWatchBridge,Z as createXRAgentService,ie as dismissHUD,tt as generateSuggestions,q as getQuestStyleOverrides,ct as getVisibleMessages,ot as initializeAndroidXR,R as initializeFenixMobile,rt as initializeQuestApp,pt as initializeVisionOS,it as pinCard,at as scrollOverlay,Ue as startMobile,st as unpinCard,oe as updateAnnotations};
|
|
603
|
+
`;function os(t,e){return e.syncVersion>t.syncVersion?"remote":t.syncVersion>e.syncVersion?"local":new Date(e.updatedAt)>=new Date(t.updatedAt)?"remote":"local"}async function Ne(t,e,r,n){let o=null;for(let s=0;s<=n;s++)try{let i=await r(t,e);if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);return i}catch(i){if(o=i instanceof Error?i:new Error(String(i)),s<n){let a=Math.pow(2,s+1)*1e3;await new Promise(c=>setTimeout(c,a))}}throw o}function Dt(t){let{serverUrl:e,authToken:r,db:n}=t,o=t.fetchFn??globalThis.fetch,s=t.maxRetries??3;n.execSync(rs);let i=e.replace(/\/$/,""),a={"Content-Type":"application/json",Authorization:`Bearer ${r}`};function c(g){return n.getFirstSync("SELECT value FROM sync_state WHERE key = ?",[g])?.value??null}function l(g,p){n.runSync(`INSERT INTO sync_state (key, value) VALUES (?, ?)
|
|
604
|
+
ON CONFLICT (key) DO UPDATE SET value = excluded.value`,[g,p])}function d(g,p,m){let y=crypto.randomUUID();n.runSync(`INSERT INTO sync_conflicts (id, entity_type, entity_id, local_version, remote_version, local_data, remote_data, resolved_to, created_at)
|
|
605
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[y,g.entityType,g.entityId,g.localVersion,g.remoteVersion,JSON.stringify(p),JSON.stringify(m),g.resolvedTo,new Date().toISOString()])}function u(g){let p=n.getAllSync("SELECT id, content, category, heat, updated_at FROM memory_segments WHERE updated_at > ? ORDER BY updated_at ASC",[g]).map(y=>({id:y.id,content:y.content,category:y.category,confidence:y.heat,syncVersion:1,updatedAt:y.updated_at})),m=n.getAllSync("SELECT id, conversation_id, role, content, created_at FROM messages WHERE created_at > ? ORDER BY created_at ASC",[g]).map(y=>({id:y.id,conversationId:y.conversation_id,role:y.role,content:y.content,syncVersion:1,createdAt:y.created_at}));return{facts:p,messages:m}}function f(g){for(let p of g){let m=n.getFirstSync("SELECT id, heat, updated_at FROM memory_segments WHERE id = ?",[p.id]);if(m){let y=os({syncVersion:1,updatedAt:m.updated_at},{syncVersion:p.syncVersion,updatedAt:p.updatedAt});y==="remote"&&n.runSync("UPDATE memory_segments SET content = ?, category = ?, heat = ?, updated_at = ? WHERE id = ?",[p.content,p.category,p.confidence,p.updatedAt,p.id]),d({entityType:"fact",entityId:p.id,localVersion:1,remoteVersion:p.syncVersion,localUpdatedAt:m.updated_at,remoteUpdatedAt:p.updatedAt,resolvedTo:y},m,p)}else{let y=p.updatedAt;n.runSync(`INSERT INTO memory_segments (id, user_id, content, category, heat, access_count, last_accessed_at, created_at, updated_at)
|
|
606
|
+
VALUES (?, 'default', ?, ?, ?, 0, ?, ?, ?)`,[p.id,p.content,p.category,p.confidence,y,y,y])}}}function T(g){for(let p of g)n.getFirstSync("SELECT id FROM messages WHERE id = ?",[p.id])||n.runSync(`INSERT INTO messages (id, conversation_id, user_id, role, content, channel, metadata, created_at)
|
|
607
|
+
VALUES (?, ?, 'default', ?, ?, 'sync', '{}', ?)`,[p.id,p.conversationId,p.role,p.content,p.createdAt])}function v(g){for(let p of g){let m=n.getFirstSync("SELECT updated_at FROM identity_files WHERE workspace_id = 'default' AND file_name = ?",[p.fileName]);if(m)new Date(p.updatedAt)>new Date(m.updated_at)&&n.runSync("UPDATE identity_files SET content = ?, updated_at = ? WHERE workspace_id = 'default' AND file_name = ?",[p.content,p.updatedAt,p.fileName]);else{let y=crypto.randomUUID();n.runSync(`INSERT INTO identity_files (id, workspace_id, file_name, content, metadata, created_at, updated_at)
|
|
608
|
+
VALUES (?, 'default', ?, ?, '{}', ?, ?)`,[y,p.fileName,p.content,p.updatedAt,p.updatedAt])}}}return{async status(){return(await Ne(`${i}/sync/status`,{method:"GET",headers:a},o,s)).json()},async push(g){let m=await(await Ne(`${i}/sync/push`,{method:"POST",headers:a,body:JSON.stringify(g)},o,s)).json();if(m.conflicts.length>0)for(let y of m.conflicts)d(y,null,null);return m},async pull(g){let m=await(await Ne(`${i}/sync/pull?since=${encodeURIComponent(g)}`,{method:"GET",headers:a},o,s)).json();return f(m.facts),T(m.messages),v(m.identity),m},async ack(g){await Ne(`${i}/sync/ack`,{method:"POST",headers:a,body:JSON.stringify({receivedUpTo:g})},o,s),l("last_sync",g)},async fullSync(){let g=c("last_sync")??"1970-01-01T00:00:00.000Z",p=u(g),m=await this.push(p),y=await this.pull(g),E=y.serverTime??m.serverTime??new Date().toISOString();return await this.ack(E),{pushed:m,pulled:y}}}}var $t="fenix-background-sync";function Ut(t){let{syncClient:e,isOnline:r,onSyncStart:n,onSyncEnd:o,registerBackgroundTask:s,unregisterBackgroundTask:i}=t,a=t.debounceMs??3e5,c=t.backgroundIntervalMs??18e5,l=null,d=!1;async function u(f){if(!r())return{success:!1,source:f,error:"offline"};if(d)return{success:!1,source:f,error:"sync_in_progress"};if(n?.(f)===!1)return{success:!1,source:f,error:"cancelled"};d=!0;try{let{pushed:v,pulled:g}=await e.fullSync(),p={success:!0,source:f,pushed:v.accepted,pulled:g.facts.length+g.messages.length+g.identity.length};return o?.(f,p),p}catch(v){let g={success:!1,source:f,error:v instanceof Error?v.message:String(v)};return o?.(f,g),g}finally{d=!1}}return{async onForeground(){return u("foreground")},onConversationIdle(){l&&clearTimeout(l),l=setTimeout(()=>{l=null,u("post_conversation")},a)},async syncNow(){return u("manual")},async onPushNotification(){return u("push")},async registerBackground(){s&&await s($t,c)},async unregisterBackground(){i&&await i($t)},executeSync:u,dispose(){l&&(clearTimeout(l),l=null)}}}async function X(t){let e=t.userId??"default",r=t.isOnline??(()=>!0),n=G(t.db);await n.initialize();let o=ye({db:t.db}),s=he(t.db),i=t.localModel?Ot(t.localModel):void 0,a=ge({cloudProvider:t.cloudProvider,localProvider:i,preferLocal:t.preferLocal??!1,isOnline:r}),c=Lt({tools:t.tools??[],isOnline:r}),l=await fe({db:t.db,cloudProvider:t.cloudProvider,localProvider:i,preferLocal:t.preferLocal,isOnline:r}),d=null,u=null,f=!!t.sync;return t.sync&&(d=Dt({serverUrl:t.sync.serverUrl,authToken:t.sync.authToken,db:t.db}),u=Ut({syncClient:d,isOnline:r,registerBackgroundTask:t.registerBackgroundTask,unregisterBackgroundTask:t.unregisterBackgroundTask}),await u.registerBackground(),u.onForeground()),{db:t.db,storage:n,identityStore:s,memorySearch:o,agent:l,userId:e,syncEnabled:f,syncPending:!1,lastSyncTime:null,isOnline:r,syncClient:d,syncTriggers:u,toolRegistry:c,dispose(){u?.dispose()}}}function ss(t){let{onMessage:e,connectivity:r}=t,n=[],o=!1;async function s(c){let l={type:c.type??"text_input",payload:String(c.payload??""),timestamp:String(c.timestamp??new Date().toISOString())};if(l.payload.trim()){await i("thinking"),o=!0;try{let{response:d,suggestions:u}=await e(l.payload);r.isReachable()?await r.sendMessage({type:"response",payload:Le(d),suggestions:u.slice(0,3)}):r.transferUserInfo({type:"response",payload:Le(d),suggestions:u.slice(0,3)})}catch(d){let u=d instanceof Error?d.message:"Something went wrong";r.isReachable()&&await r.sendMessage({type:"error",payload:Le(u)})}finally{o=!1,await i("idle")}}}async function i(c){try{r.isReachable()&&await r.sendMessage({type:"status",status:c})}catch{}}async function a(c,l){let d={type:"response",payload:Le(c)};l?.length&&(d.suggestions=l.slice(0,3)),r.isReachable()?await r.sendMessage(d):r.transferUserInfo(d)}return{start(){return r.onMessage(s)},sendStatus:i,sendResponse:a,isWatchReachable(){return r.isReachable()},getPendingQueue(){return[...n]}}}function Le(t,e=500){return t.length<=e?t:t.slice(0,e-3)+"..."}function is(t){let e=[];return t.includes("?")&&e.push("Yes","No"),t.toLowerCase().includes("remind")&&e.push("Set reminder"),(t.toLowerCase().includes("meeting")||t.toLowerCase().includes("calendar"))&&e.push("Show calendar"),e.length===0&&e.push("Tell me more","Thanks"),e.slice(0,3)}var as={trigger:"send_message",grip:"push_to_talk",thumbstick_click:"cancel"};function Ft(t={}){let e={...as,...t.mapping},r=t.voiceCapture;return{handleControllerEvent(n){if(!n.pressed)return null;let o=null;switch(n.button){case"trigger":o=e.trigger==="none"?null:e.trigger;break;case"grip":o=e.grip==="none"?null:e.grip;break;case"thumbstick_click":o=e.thumbstick_click==="none"?null:e.thumbstick_click;break;default:o=null}return o&&t.onAction?.(o,n),o},async startVoice(){if(!r)throw new Error("Voice capture not available on this device");await r.startRecording()},async stopVoice(){return!r||!r.isRecording()?null:r.stopRecording()},isRecordingVoice(){return r?.isRecording()??!1},getMapping(){return{...e}},setMapping(n){Object.assign(e,n)}}}var Oe={width:1024,height:768,backgroundOpacity:.95,fontScale:1.2,minTouchTarget:48,showSystemKeyboard:!0};function Bt(t=Oe){return{baseFontSize:Math.round(16*t.fontScale),headingFontSize:Math.round(24*t.fontScale),minTouchTarget:t.minTouchTarget,panelWidth:t.width,panelHeight:t.height,backgroundOpacity:t.backgroundOpacity}}async function cs(t){let e=await X(t),r={...Oe,...t.panel},n=Bt(r),o=Ft(t.controller);return{fenix:e,controller:o,styles:n,panel:r,dispose(){e.dispose()}}}function jt(t){let{onTranscription:e,wakeWordDetector:r}=t,n=t.isOnline??(()=>!0),o=!1,s=!1;function i(){return!n()&&t.offlineSTT?t.offlineSTT:t.sttProvider}function a(){return!n()&&t.offlineTTS?t.offlineTTS:t.ttsProvider}async function c(){if(o)return"";o=!0;try{let d=await i().stopListening();if(!d.trim())return"";let u=await e(d);return u&&await a().speak(u),u}finally{o=!1}}return{start(){s=!0,r?.start(async()=>{o||await i().startListening(()=>{})})},stop(){s=!1,r?.stop(),a().stop()},async pushToTalk(){return await i().startListening(()=>{}),c()},async speak(l){await a().speak(l)},isBusy(){return o}}}function Ht(t){let{camera:e}=t,r=t.isOnline??(()=>!0);function n(){return!r()&&t.offlineVisionProvider?t.offlineVisionProvider:t.visionProvider}return{async describeView(o){if(!e.hasPermission()&&!await e.requestPermission())return"Camera permission not granted.";let s=await e.captureFrame("main");return n().describe(s,o??"Describe what you see in this image.")},async captureFrame(){return e.hasPermission()||await e.requestPermission(),e.captureFrame("main")},isAvailable(){return e.hasPermission()}}}var qt={touchpad:{tap:"send_message",double_tap:"pin_card",long_press:"activate_agent",swipe_up:"scroll_up",swipe_down:"scroll_down",swipe_left:"dismiss",swipe_right:"none"},head:{nod:"confirm",shake:"deny",tilt_left:"none",tilt_right:"dismiss"},button:{camera_short:"none",camera_long:"activate_agent"}};function Wt(t={}){let e={touchpad:{...qt.touchpad,...t.mapping?.touchpad},head:{...qt.head,...t.mapping?.head},button:{...qt.button,...t.mapping?.button}};return{handleEvent(r){let n="none";switch(r.source){case"touchpad":n=e.touchpad[r.gesture]??"none";break;case"head":n=e.head[r.gesture]??"none";break;case"button":n=e.button[r.gesture]??"none";break}return n!=="none"&&t.onAction?.(n,r),n},getMapping(){return{touchpad:{...e.touchpad},head:{...e.head},button:{...e.button}}},setMapping(r){r.touchpad&&Object.assign(e.touchpad,r.touchpad),r.head&&Object.assign(e.head,r.head),r.button&&Object.assign(e.button,r.button)}}}function Jt(t){let e=new Map,r=t.allowedApps?new Set(t.allowedApps):null;return{async handleNotification(n){r&&!r.has(n.app)||(e.set(n.id,n),n.priority==="urgent"&&t.onSpeak&&await t.onSpeak(`Urgent from ${n.app}: ${n.title}. ${n.body}`),t.onDisplay?.(n))},getUnread(){return Array.from(e.values()).sort((n,o)=>new Date(o.timestamp).getTime()-new Date(n.timestamp).getTime())},markRead(n){e.delete(n)},clearAll(){e.clear()},async speakSummary(){let n=Array.from(e.values());if(n.length===0){await t.onSpeak?.("No new notifications.");return}let o;if(t.summarize)o=await t.summarize(n);else if(n.length===1){let s=n[0];o=`You have one notification from ${s.app}: ${s.title}`}else{let s=[...new Set(n.map(i=>i.app))];o=`You have ${n.length} notifications from ${s.join(", ")}`}await t.onSpeak?.(o)}}}function Vt(t){let e=!1,r=jt({...t.voice,onTranscription:async a=>{if(["looking at","see","what is this","what's this","describe"].some(d=>a.toLowerCase().includes(d))&&n.isAvailable()){let d=await n.captureFrame();return t.processQuery(a,d.data)}return t.processQuery(a)}}),n=Ht(t.context),o=Wt({...t.gesture,onAction:(a,c)=>{i(a),t.gesture?.onAction?.(a,c)}}),s=Jt({...t.notification,onSpeak:async a=>{await r.speak(a),t.notification?.onSpeak?.(a)}});function i(a){switch(a){case"activate_agent":r.isBusy()||r.pushToTalk();break;case"dismiss":break;case"confirm":case"deny":break}}return{start(){e=!0,r.start()},stop(){e=!1,r.stop()},isRunning(){return e},voice:r,context:n,gesture:o,notification:s}}async function ls(t){let e=await X(t),r=Vt({voice:t.voice,context:t.context,gesture:t.gesture,notification:t.notification,async processQuery(n,o){let s="",i=e.agent.run({text:n});for await(let a of i)a&&typeof a=="object"&&a.type==="token"&&(s+=a.token??"");return s||"I couldn't process that. Try again."}});return r.start(),{fenix:e,xr:r,dispose(){r.stop(),e.dispose()}}}function De(t,e,r={}){let n=r.maxBodyLength??120,o=e.length>n?e.slice(0,n-3)+"...":e;return{id:crypto.randomUUID(),title:t.slice(0,40),body:o,timestamp:new Date().toISOString(),pinned:!1,autoDismissMs:r.autoDismissMs??8e3}}function ds(t){return{...t,pinned:!0,autoDismissMs:0}}function us(t){return{...t,pinned:!1,autoDismissMs:8e3}}function Gt(t,e,r="low"){return{id:crypto.randomUUID(),app:t,text:e.slice(0,60),priority:r,timestamp:new Date().toISOString(),autoDismissMs:r==="high"?6e3:4e3}}function Xt(t=8){return{messages:[],visible:!1,scrollOffset:0,maxVisibleMessages:t}}function Kt(t,e,r){let n={id:crypto.randomUUID(),role:e,content:r,timestamp:new Date().toISOString()},o=[...t.messages,n],s=Math.max(0,o.length-t.maxVisibleMessages);return{...t,messages:o,scrollOffset:s,visible:!0}}function ps(t,e){let r=e==="up"?-1:1,n=Math.max(0,t.messages.length-t.maxVisibleMessages),o=Math.max(0,Math.min(n,t.scrollOffset+r));return{...t,scrollOffset:o}}function ms(t){return t.messages.slice(t.scrollOffset,t.scrollOffset+t.maxVisibleMessages)}function Qt(t=3){return{annotations:[],visible:!1,maxAnnotations:t}}function Yt(t,e){let r=e.sort((n,o)=>o.confidence-n.confidence).slice(0,t.maxAnnotations).map(n=>({id:n.id,content:n.content.length>80?n.content.slice(0,77)+"...":n.content,relevance:n.confidence,timestamp:new Date().toISOString()}));return{...t,annotations:r,visible:r.length>0}}function zt(t){return{...t,visible:!1,annotations:[]}}function gs(t){return t.split(/\s+/).filter(Boolean).length}function fs(t,e){let r=t.split(/\s+/).filter(Boolean);return r.length<=e?t:r.slice(0,e).join(" ")+"..."}function ys(t){let{displayType:e,compressResponse:r,onSpeak:n}=t,o=t.monocularWordBudget??50,s=t.binocularWordBudget??150,i={currentCard:null,notifications:[],conversation:Xt(),memory:Qt()};async function a(c){let l=e==="monocular"?o:s;return gs(c)<=l?c:r?r(c,l):fs(c,l)}return{async showResponse(c,l){if(e==="none"){await n?.(c);return}let d=await a(c);e==="monocular"?i.currentCard=De("Fenix",d):(i.conversation=Kt(i.conversation,"assistant",d),i.currentCard=De("Fenix",d))},showNotification(c,l,d){if(e==="none"){n?.(`${c}: ${l}`);return}let u=Gt(c,l,d);i.notifications=[...i.notifications,u]},showMemoryContext(c){e!=="none"&&(i.memory=Yt(i.memory,c))},dismiss(){i.currentCard=null,i.notifications=[],i.memory=zt(i.memory)},getDisplayType(){return e},getState(){return{...i}}}}function Zt(t){let{agent:e,identityStore:r,memorySearch:n,onResponse:o}=t,s=new Map;function i(d,u,f){o({id:d,type:u,payload:f})}async function a(d){let u=new AbortController;s.set(d.id,u);try{let f=d.payload.text,T="",v=e.run({text:f});for await(let g of v){if(u.signal.aborted)return;if(g&&typeof g=="object"&&g.type==="token"){let p=g.token??"";T+=p,i(d.id,"stream_token",{token:p})}}i(d.id,"stream_end",{response:T})}catch(f){u.signal.aborted||i(d.id,"error",{message:f.message??"Agent error"})}finally{s.delete(d.id)}}async function c(d){try{let u=d.payload.query,f=d.payload.limit??10,T=n.searchFTS(u,f);i(d.id,"result",{results:T})}catch(u){i(d.id,"error",{message:u.message??"Search error"})}}async function l(d){try{if(d.type==="identity_read"){let u=d.payload.file,f=r.read(u);i(d.id,"result",{file:u,content:f})}else{let u=d.payload.file,f=d.payload.content;r.write(u,f),i(d.id,"result",{file:u,written:!0})}}catch(u){i(d.id,"error",{message:u.message??"Identity error"})}}return{async handleRequest(d){switch(d.type){case"query":return a(d);case"cancel":let u=d.payload.requestId;s.get(u)?.abort(),s.delete(u),i(d.id,"result",{cancelled:u});return;case"memory_search":return c(d);case"identity_read":case"identity_write":return l(d);case"status":i(d.id,"result",{activeRequests:[...s.keys()],agentReady:!0});return}},cancelRequest(d){s.get(d)?.abort(),s.delete(d)},getActiveRequests(){return[...s.keys()]},dispose(){for(let d of s.values())d.abort();s.clear()}}}function en(t){let{stt:e,tts:r,onTranscription:n}=t;return{async startListening(){r.isSpeaking()&&r.stop(),await e.startListening()},async stopAndProcess(){let o=await e.stopListening();if(!o.trim())return"";let s=await n(o);return await r.speak(s),s},async speak(o){await r.speak(o)},cancelSpeech(){r.stop()},isListening(){return e.isListening()},isSpeaking(){return r.isSpeaking()}}}function nr(t){return{name:"scene_understanding",description:"Identify objects and surfaces in the user's physical environment using ARKit scene understanding.",parameters:{},async handler(){let e=await t.getSceneObjects();return{objects:e.map(r=>({label:r.label,confidence:Math.round(r.confidence*100),position:`(${r.boundingBox.x.toFixed(1)}, ${r.boundingBox.y.toFixed(1)}, ${r.boundingBox.z.toFixed(1)})`})),count:e.length}}}}function rr(t){return{name:"spatial_anchor",description:"Place or retrieve spatial anchors in the user's environment. Anchors persist across sessions.",parameters:{action:{type:"string",description:"place | list | remove"},label:{type:"string",description:"Label for the anchor (place only)"},position:{type:"object",description:"{ x, y, z } coordinates (place only)"},id:{type:"string",description:"Anchor ID (remove only)"}},async handler(e){let r=e.action;return r==="list"?{anchors:await t.getAnchors()}:r==="place"?{placed:await t.placeAnchor(e.label,e.position)}:r==="remove"?{removed:await t.removeAnchor(e.id)}:{error:"Unknown action. Use place, list, or remove."}}}}function or(t){return{name:"hand_tracking",description:"Read current hand poses and gestures via ARKit hand tracking.",parameters:{},async handler(){return{hands:(await t.getHandPoses()).map(r=>({hand:r.hand,gesture:r.gesture,confidence:Math.round(r.confidence*100)}))}}}}function sr(t){return{name:"shareplay",description:"Start or end a SharePlay session for collaborative spatial experiences.",parameters:{action:{type:"string",description:"start | end"},sessionId:{type:"string",description:"Session identifier (start only)"}},async handler(e){return e.action==="start"?t.startSharePlay?{started:await t.startSharePlay(e.sessionId)}:{error:"SharePlay not available"}:e.action==="end"?t.endSharePlay?(await t.endSharePlay(),{ended:!0}):{error:"SharePlay not available"}:{error:"Unknown action. Use start or end."}}}}function tn(t){return[nr(t),rr(t),or(t),sr(t)]}async function hs(t){let e=t.tools??[];t.nativeAPIs&&e.push(...tn(t.nativeAPIs));let r=await X({...t,tools:e}),n=Zt({agent:r.agent,identityStore:r.identityStore,memorySearch:r.memorySearch,onResponse:t.onBridgeResponse??(()=>{})}),o=null;return t.voice&&(o=en(t.voice)),{fenix:r,bridge:n,voice:o,mode:t.mode,dispose(){n.dispose(),r.dispose()}}}export{Oe as DEFAULT_PANEL_CONFIG,Nt as EDITION,Rt as KERNEL_VERSION,zn as MOBILE_KERNEL_CONFIG,jo as MOBILE_MANIFEST,$t as SYNC_TASK_NAME,Kt as appendMessage,es as bootApp,_e as bootKernel,qo as bootMobile,Zt as createAgentBridge,Vo as createCalendarTool,Xo as createCameraTool,Go as createContactsTool,Ht as createContextCapture,Xt as createConversationOverlay,ys as createDisplayManager,Wt as createGestureHandler,De as createGlanceCard,or as createHandTrackingTool,ge as createHybridRouter,he as createIdentityStore,It as createKernel,Ot as createLocalProvider,Ko as createLocationTool,Qt as createMemoryHUD,ye as createMemorySearch,fe as createMobileAgent,Lt as createMobileToolRegistry,Jt as createNotificationBridge,Gt as createNotificationPill,Yo as createNotificationsTool,Ft as createQuestAdapter,Qo as createRemindersTool,G as createSQLiteAdapter,nr as createSceneUnderstandingTool,sr as createSharePlayTool,rr as createSpatialAnchorTool,Dt as createSyncClient,Ut as createSyncTriggers,tn as createVisionOSTools,en as createVisionVoiceInterface,jt as createVoiceInterface,ss as createWatchBridge,Vt as createXRAgentService,zt as dismissHUD,is as generateSuggestions,Bt as getQuestStyleOverrides,ms as getVisibleMessages,ls as initializeAndroidXR,X as initializeFenixMobile,cs as initializeQuestApp,hs as initializeVisionOS,ds as pinCard,ps as scrollOverlay,Ho as startMobile,us as unpinCard,Yt as updateAnnotations};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fenixforce/edition-mobile",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
"dist"
|
|
24
24
|
],
|
|
25
25
|
"scripts": {
|
|
26
|
-
"build": "esbuild src/index.ts --bundle --format=esm --platform=node --target=es2022 --minify --outfile=dist/index.js --external
|
|
26
|
+
"build": "esbuild src/index.ts --bundle --format=esm --platform=node --target=es2022 --minify --outfile=dist/index.js --external:pg --external:expo-sqlite --external:expo-secure-store --external:react --external:react-native && tsc --emitDeclarationOnly --project tsconfig.build.json",
|
|
27
27
|
"start": "npx expo start",
|
|
28
28
|
"test": "bun test",
|
|
29
29
|
"typecheck": "tsc --noEmit"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"
|
|
32
|
+
"pg": "^8.13.0",
|
|
33
33
|
"expo": "~52.0.0",
|
|
34
34
|
"expo-router": "~4.0.0",
|
|
35
35
|
"expo-sqlite": "~15.0.0",
|