@shawnstack/quickforge 1.7.6 → 1.7.7
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/assets/{AgentProfilesPage-Dl5Peqov.js → AgentProfilesPage-BfA_sQ3A.js} +1 -1
- package/dist/assets/{ChatPanelHost-D3987TUJ.js → ChatPanelHost-Dul1ahKj.js} +1 -1
- package/dist/assets/{CloudAccountSettingsPage-BG5Nn3bq.js → CloudAccountSettingsPage-qZh0lTUN.js} +1 -1
- package/dist/assets/{PluginsPage-BDKYfLna.js → PluginsPage-CPE5tbbf.js} +1 -1
- package/dist/assets/{ScheduledTasksPage--GAki3lB.js → ScheduledTasksPage-PTxL_PPg.js} +1 -1
- package/dist/assets/{SettingsWorkspacePage-DSy66Tuw.js → SettingsWorkspacePage-BE2T4d3P.js} +5 -5
- package/dist/assets/{ShareLinksSettingsPage-BQQMsvJo.js → ShareLinksSettingsPage-Bl8fP62X.js} +1 -1
- package/dist/assets/{SharedConversationPage-B9BUVCri.js → SharedConversationPage-BK9XJnEe.js} +1 -1
- package/dist/assets/{TerminalDock-CT1nYo7P.js → TerminalDock-CL7HU9DI.js} +1 -1
- package/dist/assets/{WorkspaceInspector-BnfDLf9a.js → WorkspaceInspector-MNBLIKMn.js} +1 -1
- package/dist/assets/{index-BivLuZvX.js → index-BTPzyq7d.js} +3 -3
- package/dist/assets/{index-1ei6nhs-.css → index-BiCTgUlY.css} +1 -1
- package/dist/assets/{mcp-servers-dialog-BEV4_TXC.js → mcp-servers-dialog-GY7sdfIr.js} +1 -1
- package/dist/assets/{skills-dialog-BTJ7mzk_.js → skills-dialog-C1fJ1Jl7.js} +1 -1
- package/dist/index.html +4 -4
- package/package.json +1 -1
- package/server/auto-compaction.mjs +43 -1
- package/server/cloud/config.mjs +8 -16
- package/server/context-usage.mjs +11 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{A as t,E as n,Wt as r,_ as i,dt as a,q as o,qt as s,s as c,x as l}from"./icons-2D18YbSI.js";import{n as u}from"./react-vendor-3UaA-C9W.js";import{B as d,Tt as f,fn as p,hn as m,mn as h,yn as g}from"./index-
|
|
1
|
+
import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{A as t,E as n,Wt as r,_ as i,dt as a,q as o,qt as s,s as c,x as l}from"./icons-2D18YbSI.js";import{n as u}from"./react-vendor-3UaA-C9W.js";import{B as d,Tt as f,fn as p,hn as m,mn as h,yn as g}from"./index-BTPzyq7d.js";var _=e(s(),1),v=u();function y(e){return e===`connected`?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:e===`error`?`bg-destructive/12 text-destructive`:e===`disabled`?`bg-muted text-muted-foreground`:`bg-amber-500/12 text-amber-700 dark:text-amber-300`}var b=12;function x({server:e,toggling:n,reconnecting:r,onToggle:i,onEdit:a,onDelete:s,onReconnect:u}){let d=e.tools?.slice(0,b)??[],f=e.toolCount??e.tools?.length??0,p=Math.max(0,f-d.length),_=e.enabled&&e.status!==`connected`;return(0,v.jsxs)(`div`,{className:`rounded-lg border border-border p-3`,children:[(0,v.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,v.jsxs)(`div`,{className:`min-w-0`,children:[(0,v.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,v.jsx)(`div`,{className:`truncate text-sm font-medium text-foreground/90`,children:e.name}),(0,v.jsx)(`span`,{className:m(`rounded-full px-2 py-0.5 text-[11px]`,y(e.status)),children:e.status||`unknown`}),(0,v.jsx)(`span`,{className:`text-[11px] text-muted-foreground/60`,children:g(`mcpToolsCount`,{count:f})})]}),(0,v.jsx)(`div`,{className:`mt-1 truncate text-xs text-muted-foreground/65`,children:e.transport===`stdio`?`${e.command} ${(e.args||[]).join(` `)}`:e.url}),e.error?(0,v.jsx)(`div`,{className:`mt-1 text-xs text-destructive`,children:e.error}):null]}),(0,v.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1`,children:[(0,v.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":e.enabled,disabled:n,className:m(`relative h-6 w-11 rounded-full transition-colors disabled:cursor-not-allowed disabled:opacity-60`,e.enabled?`bg-emerald-500`:`bg-muted-foreground/30`),onClick:()=>i(e),title:e.enabled?g(`pauseTask`):g(`enable`),children:(0,v.jsx)(`span`,{className:m(`absolute left-0.5 top-0.5 size-5 rounded-full bg-white shadow transition-transform`,e.enabled?`translate-x-5`:`translate-x-0`)})}),_?(0,v.jsx)(h,{type:`button`,variant:`ghost`,size:`icon`,className:`size-8 text-muted-foreground`,onClick:()=>u(e.name),disabled:r,"aria-label":g(`mcpReconnectServer`),title:g(`mcpReconnectServer`),children:r?(0,v.jsx)(o,{className:`size-4 animate-spin`}):(0,v.jsx)(l,{className:`size-4`})}):null,(0,v.jsx)(h,{type:`button`,variant:`ghost`,size:`icon`,className:`size-8 text-muted-foreground`,onClick:()=>a(e),"aria-label":g(`editTask`),title:g(`editTask`),children:(0,v.jsx)(t,{className:`size-4`})}),(0,v.jsx)(h,{type:`button`,variant:`ghost`,size:`icon`,className:`size-8 text-destructive`,onClick:()=>s(e.name),"aria-label":g(`delete`),title:g(`delete`),children:(0,v.jsx)(c,{className:`size-4`})})]})]}),d.length>0?(0,v.jsxs)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:[d.map(e=>(0,v.jsx)(`span`,{className:`rounded-md bg-muted/28 px-1.5 py-0.5 text-[11px] text-muted-foreground/75`,title:e.quickForgeName,children:e.name},e.quickForgeName)),p>0?(0,v.jsx)(`span`,{className:`rounded-md px-1.5 py-0.5 text-[11px] text-muted-foreground/55`,children:g(`mcpMoreTools`,{count:p})}):null]}):null]})}function S(){return{name:``,transport:`stdio`,command:``,args:[],url:``,cwd:``,env:{}}}function C(e){return{name:e.name,transport:e.transport,command:e.command,args:e.args||[],url:e.url||``,cwd:e.cwd||``,env:e.env||{}}}function w(e){return(e||[]).join(`
|
|
2
2
|
`)}function T(e){return Object.entries(e||{}).map(([e,t])=>`${e}=${t}`).join(`
|
|
3
3
|
`)}function E(e){return e.split(`
|
|
4
4
|
`).map(e=>e.trim()).filter(Boolean)}function D(e){let t={};for(let n of e.split(`
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{i as e,n as t}from"./rolldown-runtime-DWdDZTNf.js";import{Wt as n,n as r,q as i,qt as a,y as o,zt as s}from"./icons-2D18YbSI.js";import{n as c}from"./react-vendor-3UaA-C9W.js";import{fn as l,hn as u,yn as d}from"./index-
|
|
1
|
+
import{i as e,n as t}from"./rolldown-runtime-DWdDZTNf.js";import{Wt as n,n as r,q as i,qt as a,y as o,zt as s}from"./icons-2D18YbSI.js";import{n as c}from"./react-vendor-3UaA-C9W.js";import{fn as l,hn as u,yn as d}from"./index-BTPzyq7d.js";var f=t({SkillsDialog:()=>_,SkillsManagerPanel:()=>g}),p=e(a(),1),m=c();async function h(e){let t=await e.json().catch(()=>null);if(!e.ok)throw Error(t?.error||`HTTP ${e.status}`);return t}function g({active:e=!0,scope:t,project:a,embedded:c=!1,onClose:f,onSaved:g}){let[_,v]=(0,p.useState)([]),[y,b]=(0,p.useState)(()=>new Set),[x,S]=(0,p.useState)(``),[C,w]=(0,p.useState)([]),[T,E]=(0,p.useState)(!1),[D,O]=(0,p.useState)(!1),[k,A]=(0,p.useState)(``),j=t===`project`,[M,N]=(0,p.useState)(null),[P,F]=(0,p.useState)(null),[I,L]=(0,p.useState)(!1),[R,z]=(0,p.useState)(``),B=(0,p.useCallback)(()=>{N(null),F(null),z(``)},[]),V=(0,p.useCallback)(()=>{B(),f?.()},[f,B]);(0,p.useEffect)(()=>{if(!e||j&&!a)return;let t=!1;return(async()=>{E(!0),A(``);try{let e=j?`/api/skills?projectId=${encodeURIComponent(a.id)}`:`/api/skills?scope=global`,n=await h(await fetch(e));if(t)return;v(Array.isArray(n.skills)?n.skills:[]),b(new Set(Array.isArray(n.selectedSkills)?n.selectedSkills:[])),w(Array.isArray(n.searchPaths)?n.searchPaths:[])}catch(e){t||A(e instanceof Error?e.message:d(`failedToLoadSkills`))}finally{t||E(!1)}})(),()=>{t=!0}},[e,a,j]),(0,p.useEffect)(()=>{if(!e||c)return;let t=e=>{e.key===`Escape`&&(M?B():D||V())};return document.addEventListener(`keydown`,t),()=>document.removeEventListener(`keydown`,t)},[e,V,c,D,M,B]);let H=(0,p.useMemo)(()=>{let e=x.trim().toLowerCase();return e?_.filter(t=>[t.name,t.displayName,t.description,t.source,t.compatibility,t.allowedTools,...t.tags??[],...t.triggers??[]].filter(Boolean).join(` `).toLowerCase().includes(e)):_},[x,_]),U=async e=>{N(e),F(null),z(``),L(!0);try{let t=new URLSearchParams({name:e});j&&a?(t.set(`scope`,`project`),t.set(`projectId`,a.id)):t.set(`scope`,`global`),F(await h(await fetch(`/api/skills/content?${t}`)))}catch(e){z(e instanceof Error?e.message:d(`failedToReadSkill`))}finally{L(!1)}};if(!e||j&&!a)return null;let W=e=>{if(D)return;let t=new Set(y);t.has(e)?t.delete(e):t.add(e),b(t),G(t)},G=async e=>{O(!0),A(``);try{let n=await h(await fetch(j?`/api/skills/project`:`/api/skills/global`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify(j?{projectId:a.id,selectedSkills:[...e]}:{selectedSkills:[...e]})}));g({scope:t,project:j?n.projects?.find(e=>e.id===a.id)??{...a,skills:n.selectedSkills}:void 0,projects:n.projects,selectedSkills:n.selectedSkills})}catch(e){b(y),A(e instanceof Error?e.message:d(`failedToSaveSkills`))}finally{O(!1)}},K=d(j?`projectSkills`:`globalSkills`),q=j?d(`projectSkillsDescription`,{project:a.name}):d(`globalSkillsDescription`),J=(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`div`,{className:`quickforge-settings-divider p-3`,children:(0,m.jsxs)(`div`,{className:`quickforge-settings-inline-field`,children:[(0,m.jsx)(o,{className:`pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground/60`}),(0,m.jsx)(`input`,{value:x,onChange:e=>S(e.target.value),placeholder:d(`searchSkills`),className:`quickforge-settings-input`,disabled:T||D})]})}),k?(0,m.jsx)(`div`,{className:`quickforge-settings-alert quickforge-settings-warning-attached`,children:k}):null,(0,m.jsxs)(`div`,{className:`quickforge-settings-toolbar`,children:[(0,m.jsx)(`span`,{className:`quickforge-settings-row-title`,children:d(`availableSkills`)}),(0,m.jsx)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-info`,children:d(`selectedSkillsCount`,{count:y.size})})]}),(0,m.jsx)(`div`,{className:c?``:`max-h-[46vh] overflow-y-auto`,children:T?(0,m.jsxs)(`div`,{className:`quickforge-settings-empty-row inline-flex items-center gap-2`,children:[(0,m.jsx)(i,{className:`size-4 animate-spin`}),d(`loading`)]}):H.length===0?(0,m.jsx)(`div`,{className:`quickforge-settings-empty-row`,children:d(`noMatchingSkills`)}):H.map(e=>{let t=y.has(e.name);return(0,m.jsxs)(`div`,{className:u(`quickforge-settings-list-item`,t&&`bg-muted/12`),children:[(0,m.jsxs)(`div`,{className:`quickforge-settings-list-item-main`,children:[(0,m.jsx)(`div`,{className:`quickforge-settings-row-title`,children:e.displayName||e.name}),e.description?(0,m.jsx)(`div`,{className:`quickforge-settings-row-description`,children:e.description}):null,(0,m.jsxs)(`div`,{className:`quickforge-settings-meta`,children:[e.source?(0,m.jsx)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-muted`,children:e.source}):null,e.compatibility?(0,m.jsx)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-muted`,children:e.compatibility}):null,e.allowedTools?(0,m.jsx)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-muted`,children:e.allowedTools}):null,e.tags?.slice(0,5).map(e=>(0,m.jsx)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-muted`,children:e},e))]})]}),(0,m.jsxs)(`div`,{className:`quickforge-settings-list-item-actions`,onClick:e=>e.stopPropagation(),children:[(0,m.jsxs)(`label`,{className:`quickforge-settings-switch`,"aria-disabled":D?`true`:`false`,children:[(0,m.jsx)(`input`,{type:`checkbox`,checked:t,disabled:D,onChange:()=>W(e.name),"aria-label":t?`Disable ${e.name}`:`Enable ${e.name}`}),(0,m.jsx)(`span`,{"aria-hidden":`true`})]}),(0,m.jsx)(`button`,{type:`button`,className:`quickforge-settings-icon-action`,onClick:()=>void U(e.name),disabled:D||I,title:d(`readSkill`),"aria-label":`${d(`readSkill`)}: ${e.displayName||e.name}`,children:(0,m.jsx)(s,{className:`size-4`})})]})]},e.name)})})]}),Y=(0,m.jsxs)(m.Fragment,{children:[(0,m.jsxs)(`div`,{className:`quickforge-settings-toolbar`,children:[(0,m.jsxs)(`button`,{type:`button`,className:`quickforge-settings-button quickforge-settings-button-secondary`,onClick:B,disabled:I,children:[(0,m.jsx)(n,{className:`mr-2 size-4`}),d(`backToSkillList`)]}),(0,m.jsx)(`div`,{className:`quickforge-settings-row-main min-w-0`,children:(0,m.jsx)(`div`,{className:`quickforge-settings-row-title truncate`,children:P?.displayName||P?.name||M})})]}),(0,m.jsx)(`div`,{className:`p-4`,children:I?(0,m.jsxs)(`div`,{className:`quickforge-settings-empty-row inline-flex items-center gap-2`,children:[(0,m.jsx)(i,{className:`size-4 animate-spin`}),d(`loading`)]}):R?(0,m.jsx)(`div`,{className:`quickforge-settings-alert quickforge-settings-warning-attached`,children:R}):P?(0,m.jsxs)(m.Fragment,{children:[P.description?(0,m.jsx)(`div`,{className:`quickforge-settings-row-description mb-3`,children:P.description}):null,(0,m.jsxs)(`div`,{className:`quickforge-settings-meta mb-3`,children:[P.version?(0,m.jsxs)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-muted`,children:[`v`,P.version]}):null,P.source?(0,m.jsx)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-muted`,children:P.source}):null,P.compatibility?(0,m.jsx)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-muted`,children:P.compatibility}):null,P.allowedTools?(0,m.jsx)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-muted`,children:P.allowedTools}):null,P.license?(0,m.jsx)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-muted`,children:P.license}):null,P.tags?.map(e=>(0,m.jsx)(`span`,{className:`quickforge-settings-badge quickforge-settings-badge-muted`,children:e},e))]}),P.triggers?.length?(0,m.jsxs)(`div`,{className:`quickforge-settings-row-description mb-3`,children:[`Triggers: `,P.triggers.join(`, `)]}):null,P.instructions?(0,m.jsx)(`pre`,{className:`whitespace-pre-wrap break-words rounded-md border border-border bg-muted/30 px-4 py-3 font-mono text-sm leading-6 text-foreground/80`,children:P.instructions}):(0,m.jsx)(`div`,{className:`quickforge-settings-empty-row`,children:d(`noSkillContent`)})]}):null})]});return c?(0,m.jsx)(`div`,{className:`quickforge-settings-stack`,children:(0,m.jsx)(`section`,{className:`quickforge-settings-section`,"aria-label":K,children:M?Y:(0,m.jsxs)(m.Fragment,{children:[C.length?(0,m.jsx)(`div`,{className:`px-5 pt-4`,children:(0,m.jsxs)(`span`,{className:`quickforge-settings-row-description inline-flex items-center`,children:[d(`skillSearchPaths`),(0,m.jsx)(l,{label:C.join(`
|
|
2
2
|
`)})]})}):null,J]})})}):(0,m.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4`,onClick:e=>{e.target===e.currentTarget&&!D&&V()},children:(0,m.jsxs)(`div`,{className:`flex max-h-[85vh] w-full max-w-2xl flex-col rounded-lg border border-border bg-background shadow-quickforge`,children:[(0,m.jsxs)(`div`,{className:`quickforge-settings-toolbar`,children:[(0,m.jsxs)(`div`,{className:`quickforge-settings-row-main`,children:[(0,m.jsxs)(`div`,{className:`quickforge-settings-row-title`,children:[K,(0,m.jsx)(l,{label:q})]}),(0,m.jsx)(`div`,{className:`quickforge-settings-row-description`,children:q}),C.length?(0,m.jsxs)(`div`,{className:`quickforge-settings-row-description inline-flex items-center`,children:[d(`skillSearchPaths`),(0,m.jsx)(l,{label:C.join(`
|
|
3
3
|
`)})]}):null]}),(0,m.jsx)(`button`,{type:`button`,className:`quickforge-settings-icon-action`,onClick:V,disabled:D,"aria-label":d(`close`),children:(0,m.jsx)(r,{className:`size-4`})})]}),(0,m.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto`,children:M?Y:J})]})})}function _({open:e,scope:t,project:n,onOpenChange:r,onSaved:i}){return(0,m.jsx)(g,{active:e,scope:t,project:n,onClose:()=>r(!1),onSaved:i})}export{f as n,_ as t};
|
package/dist/index.html
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<meta name="apple-mobile-web-app-title" content="QuickForge" />
|
|
12
12
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
13
13
|
<title>速构 QuickForge</title>
|
|
14
|
-
<script type="module" crossorigin src="/assets/index-
|
|
14
|
+
<script type="module" crossorigin src="/assets/index-BTPzyq7d.js"></script>
|
|
15
15
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-DWdDZTNf.js">
|
|
16
16
|
<link rel="modulepreload" crossorigin href="/assets/pi-ai-Cr2ee4a0.js">
|
|
17
17
|
<link rel="modulepreload" crossorigin href="/assets/dist-yDHbi5ux.js">
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
<link rel="modulepreload" crossorigin href="/assets/react-vendor-3UaA-C9W.js">
|
|
23
23
|
<link rel="modulepreload" crossorigin href="/assets/model-display-label-C6-0eDxF.js">
|
|
24
24
|
<link rel="modulepreload" crossorigin href="/assets/model-reference-o41fJ6jQ.js">
|
|
25
|
-
<link rel="modulepreload" crossorigin href="/assets/index-
|
|
26
|
-
<link rel="modulepreload" crossorigin href="/assets/skills-dialog-
|
|
27
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
25
|
+
<link rel="modulepreload" crossorigin href="/assets/index-BTPzyq7d.js">
|
|
26
|
+
<link rel="modulepreload" crossorigin href="/assets/skills-dialog-C1fJ1Jl7.js">
|
|
27
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BiCTgUlY.css">
|
|
28
28
|
</head>
|
|
29
29
|
<body>
|
|
30
30
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -175,6 +175,46 @@ export function buildAutoCompactLoopMessages(session, messages) {
|
|
|
175
175
|
return [summaryMessage, ...source.slice(tailStart)]
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
function messageTimestampMs(message) {
|
|
179
|
+
const value = message?.timestamp
|
|
180
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value
|
|
181
|
+
if (typeof value === 'string') {
|
|
182
|
+
const parsed = Date.parse(value)
|
|
183
|
+
if (Number.isFinite(parsed)) return parsed
|
|
184
|
+
}
|
|
185
|
+
return 0
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function minimumProviderUsageIndex(session, messages) {
|
|
189
|
+
if (!session?.contextCompaction?.summaryMessage) return 0
|
|
190
|
+
const source = Array.isArray(messages) ? messages : []
|
|
191
|
+
const compactedUpToIndex = Math.min(source.length, Math.max(0, Number(session.contextCompaction.compactedUpToIndex) || 0))
|
|
192
|
+
let tailStart = compactedUpToIndex
|
|
193
|
+
while (tailStart < source.length && isToolResultMessage(source[tailStart])) tailStart += 1
|
|
194
|
+
|
|
195
|
+
const compactedAt = Date.parse(session.contextCompaction.compactedAt || '')
|
|
196
|
+
if (Number.isFinite(compactedAt)) {
|
|
197
|
+
const firstNewMessageIndex = source.findIndex((message) => messageTimestampMs(message) > compactedAt)
|
|
198
|
+
if (firstNewMessageIndex >= 0) return Math.max(1, firstNewMessageIndex - tailStart + 1)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const sourceMessageCount = Number(session.contextCompaction.sourceMessageCount)
|
|
202
|
+
if (Number.isFinite(sourceMessageCount) && sourceMessageCount > 0 && source.length >= sourceMessageCount) {
|
|
203
|
+
return Math.max(1, sourceMessageCount - tailStart + 1)
|
|
204
|
+
}
|
|
205
|
+
return source.length - tailStart + 1
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function hasNewMessagesSinceCompaction(session, messages) {
|
|
209
|
+
if (!session?.contextCompaction?.summaryMessage) return true
|
|
210
|
+
const source = Array.isArray(messages) ? messages : []
|
|
211
|
+
const sourceMessageCount = Number(session.contextCompaction.sourceMessageCount)
|
|
212
|
+
if (Number.isFinite(sourceMessageCount) && sourceMessageCount > 0 && source.length > sourceMessageCount) return true
|
|
213
|
+
|
|
214
|
+
const compactedAt = Date.parse(session.contextCompaction.compactedAt || '')
|
|
215
|
+
return Number.isFinite(compactedAt) && source.some((message) => messageTimestampMs(message) > compactedAt)
|
|
216
|
+
}
|
|
217
|
+
|
|
178
218
|
export async function compactSessionInPlace({
|
|
179
219
|
session,
|
|
180
220
|
messages,
|
|
@@ -308,6 +348,7 @@ export function estimateSessionContextUsage(session, messages = session?.agent?.
|
|
|
308
348
|
messages: loopMessages,
|
|
309
349
|
tools: session.agent.state.tools,
|
|
310
350
|
model: session.model,
|
|
351
|
+
minimumProviderUsageIndex: minimumProviderUsageIndex(session, sourceMessages),
|
|
311
352
|
})
|
|
312
353
|
value.isCompacted = loopMessages !== sourceMessages
|
|
313
354
|
value.originalMessageCount = sourceMessages.length
|
|
@@ -332,6 +373,7 @@ export async function maybeAutoCompactSession({ session, messages, signal, emitS
|
|
|
332
373
|
messages: loopMessages,
|
|
333
374
|
tools: session.agent.state.tools,
|
|
334
375
|
model: session.model,
|
|
376
|
+
minimumProviderUsageIndex: minimumProviderUsageIndex(session, messages),
|
|
335
377
|
})
|
|
336
378
|
if (!usage.contextWindow) return { compacted: false, usage, reason: 'missing_context_window' }
|
|
337
379
|
if (!shouldCompactContextByPercent(usage, settings.thresholdPercent)) return { compacted: false, usage, reason: 'below_threshold' }
|
|
@@ -341,7 +383,7 @@ export async function maybeAutoCompactSession({ session, messages, signal, emitS
|
|
|
341
383
|
if (session.lastAutoCompactAt && now - session.lastAutoCompactAt < AUTO_COMPACT_MIN_INTERVAL_MS) {
|
|
342
384
|
return { compacted: false, usage, reason: 'recently_compacted' }
|
|
343
385
|
}
|
|
344
|
-
if (session
|
|
386
|
+
if (!hasNewMessagesSinceCompaction(session, messages)) {
|
|
345
387
|
return { compacted: false, usage, reason: 'not_enough_new_messages' }
|
|
346
388
|
}
|
|
347
389
|
|
package/server/cloud/config.mjs
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import net from 'node:net'
|
|
2
|
-
|
|
3
1
|
const DEFAULT_TIMEOUT_MS = 10_000
|
|
4
2
|
|
|
5
|
-
function
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (ip === 4) return host.startsWith('127.')
|
|
10
|
-
if (ip === 6) return host === '::1' || host === '0:0:0:0:0:0:0:1'
|
|
11
|
-
return false
|
|
3
|
+
function invalidUrl(message) {
|
|
4
|
+
const error = new Error(message)
|
|
5
|
+
error.statusCode = 400
|
|
6
|
+
return error
|
|
12
7
|
}
|
|
13
8
|
|
|
14
9
|
export function parseCloudBaseUrl(value, _options = {}) {
|
|
@@ -19,19 +14,16 @@ export function parseCloudBaseUrl(value, _options = {}) {
|
|
|
19
14
|
try {
|
|
20
15
|
url = new URL(raw)
|
|
21
16
|
} catch {
|
|
22
|
-
throw
|
|
17
|
+
throw invalidUrl('QuickForge Cloud URL must be a valid URL.')
|
|
23
18
|
}
|
|
24
19
|
|
|
25
20
|
if (url.username || url.password || url.search || url.hash) {
|
|
26
|
-
throw
|
|
21
|
+
throw invalidUrl('QuickForge Cloud URL must not contain credentials, query parameters, or fragments.')
|
|
27
22
|
}
|
|
28
23
|
if (url.protocol !== 'https:' && url.protocol !== 'http:') {
|
|
29
|
-
throw
|
|
30
|
-
}
|
|
31
|
-
if (url.protocol === 'http:' && !isLoopbackHost(url.hostname)) {
|
|
32
|
-
throw new Error('QUICKFORGE_CLOUD_URL over HTTP is only allowed for loopback hosts.')
|
|
24
|
+
throw invalidUrl('QuickForge Cloud URL must use http or https.')
|
|
33
25
|
}
|
|
34
|
-
if (url.pathname.includes('..')) throw
|
|
26
|
+
if (url.pathname.includes('..')) throw invalidUrl('QuickForge Cloud URL contains an unsafe path.')
|
|
35
27
|
url.pathname = `${url.pathname.replace(/\/+$/, '')}/`
|
|
36
28
|
return url
|
|
37
29
|
}
|
package/server/context-usage.mjs
CHANGED
|
@@ -48,7 +48,7 @@ function localMessagesTokens(messages) {
|
|
|
48
48
|
return normalizeMessagesForTokenEstimate(messages).reduce((total, message) => total + estimateTokens(message), 0)
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
export function estimateContextUsage({ systemPrompt, messages, tools, model }) {
|
|
51
|
+
export function estimateContextUsage({ systemPrompt, messages, tools, model, minimumProviderUsageIndex = 0 }) {
|
|
52
52
|
const contextWindow = Number(model?.contextWindow) || 0
|
|
53
53
|
const reservedOutputTokens = Math.max(0, Number(model?.maxTokens) || 4096)
|
|
54
54
|
const normalizedMessages = normalizeMessagesForTokenEstimate(messages)
|
|
@@ -57,7 +57,12 @@ export function estimateContextUsage({ systemPrompt, messages, tools, model }) {
|
|
|
57
57
|
const toolsTokens = textTokens(safeJson(tools))
|
|
58
58
|
const messagesTokens = localMessagesTokens(normalizedMessages)
|
|
59
59
|
const estimatedInputTokens = systemPromptTokens + messagesTokens + toolsTokens
|
|
60
|
-
const
|
|
60
|
+
const normalizedMinimumProviderUsageIndex = Math.max(0, Number(minimumProviderUsageIndex) || 0)
|
|
61
|
+
const providerUsageIndex = Number.isInteger(coreEstimate.lastUsageIndex) ? coreEstimate.lastUsageIndex : -1
|
|
62
|
+
const providerUsageTokens = providerUsageIndex >= normalizedMinimumProviderUsageIndex
|
|
63
|
+
? Math.max(0, Number(coreEstimate.usageTokens) || 0)
|
|
64
|
+
: 0
|
|
65
|
+
const providerBasedContextTokens = providerUsageTokens > 0
|
|
61
66
|
? Math.max(0, Number(coreEstimate.tokens) || 0)
|
|
62
67
|
: 0
|
|
63
68
|
const inputTokens = providerBasedContextTokens > 0
|
|
@@ -84,8 +89,10 @@ export function estimateContextUsage({ systemPrompt, messages, tools, model }) {
|
|
|
84
89
|
messagesTokens,
|
|
85
90
|
toolsTokens,
|
|
86
91
|
reservedOutputTokens,
|
|
87
|
-
providerUsageTokens
|
|
88
|
-
trailingTokens:
|
|
92
|
+
providerUsageTokens,
|
|
93
|
+
trailingTokens: providerUsageTokens > 0
|
|
94
|
+
? Math.max(0, Number(coreEstimate.trailingTokens) || 0)
|
|
95
|
+
: messagesTokens,
|
|
89
96
|
lastUsageIndex: coreEstimate.lastUsageIndex,
|
|
90
97
|
localEstimatedContextTokens: estimatedInputTokens,
|
|
91
98
|
},
|