@aexol/spectral 0.9.32 → 0.9.36
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/commands/serve.js +1 -1
- package/dist/extensions/aexol-mcp.d.ts.map +1 -1
- package/dist/extensions/aexol-mcp.js +20 -18
- package/dist/extensions/kanban-bridge.d.ts.map +1 -1
- package/dist/extensions/kanban-bridge.js +12 -8
- package/dist/relay/dispatcher.d.ts.map +1 -1
- package/dist/relay/dispatcher.js +9 -0
- package/dist/server/agent-bridge.d.ts +18 -0
- package/dist/server/agent-bridge.d.ts.map +1 -1
- package/dist/server/agent-bridge.js +47 -0
- package/dist/server/session-stream.d.ts +8 -0
- package/dist/server/session-stream.d.ts.map +1 -1
- package/dist/server/session-stream.js +15 -0
- package/dist/studio-binding.d.ts +11 -14
- package/dist/studio-binding.d.ts.map +1 -1
- package/dist/studio-binding.js +19 -23
- package/package.json +1 -1
package/dist/commands/serve.js
CHANGED
|
@@ -381,7 +381,7 @@ export async function runServe(opts = {}) {
|
|
|
381
381
|
const reconcileStudioBinding = () => {
|
|
382
382
|
void (async () => {
|
|
383
383
|
try {
|
|
384
|
-
const binding = await readStudioBinding();
|
|
384
|
+
const binding = await readStudioBinding(cwd);
|
|
385
385
|
if (!binding)
|
|
386
386
|
return;
|
|
387
387
|
// The CLI-local projectId field is required by the meta-event shape.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aexol-mcp.d.ts","sourceRoot":"","sources":["../../src/extensions/aexol-mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"aexol-mcp.d.ts","sourceRoot":"","sources":["../../src/extensions/aexol-mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAoC,MAAM,8BAA8B,CAAC;AAqFnG,wBAA8B,iBAAiB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA2RhF"}
|
|
@@ -110,21 +110,23 @@ export default async function aexolMcpExtension(ext) {
|
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
112
|
const client = new AexolMcpClient(apiUrl, token);
|
|
113
|
-
// ---- Load local Studio binding
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
(
|
|
120
|
-
|
|
113
|
+
// ---- Load local Studio binding on session start --------------------------
|
|
114
|
+
ext.on("session_start", async (_event, ctx) => {
|
|
115
|
+
try {
|
|
116
|
+
currentBinding = await readStudioBinding(ctx.cwd);
|
|
117
|
+
if (currentBinding) {
|
|
118
|
+
const displayName = currentBinding.name ?? currentBinding.projectId;
|
|
119
|
+
process.stderr.write(`[aexol-mcp] Studio binding found: ${displayName} (${currentBinding.projectId})` +
|
|
120
|
+
(currentBinding.teamId ? `, team ${currentBinding.teamId}` : "") +
|
|
121
|
+
`\n`);
|
|
122
|
+
}
|
|
121
123
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
126
|
+
process.stderr.write(`[aexol-mcp] Failed to read Studio binding: ${msg}\n`);
|
|
127
|
+
// Non-fatal — remote tools still work with explicit teamId/projectId.
|
|
128
|
+
}
|
|
129
|
+
});
|
|
128
130
|
let tools;
|
|
129
131
|
try {
|
|
130
132
|
tools = await client.listTools();
|
|
@@ -237,7 +239,7 @@ export default async function aexolMcpExtension(ext) {
|
|
|
237
239
|
},
|
|
238
240
|
required: ["projectId"],
|
|
239
241
|
},
|
|
240
|
-
async execute(_toolCallId, params) {
|
|
242
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
241
243
|
const p = params;
|
|
242
244
|
if (!p.projectId || typeof p.projectId !== "string") {
|
|
243
245
|
return {
|
|
@@ -251,7 +253,7 @@ export default async function aexolMcpExtension(ext) {
|
|
|
251
253
|
...(p.name ? { name: p.name } : {}),
|
|
252
254
|
};
|
|
253
255
|
try {
|
|
254
|
-
await writeStudioBinding(binding);
|
|
256
|
+
await writeStudioBinding(binding, ctx.cwd);
|
|
255
257
|
currentBinding = binding;
|
|
256
258
|
const displayName = binding.name ?? binding.projectId;
|
|
257
259
|
return {
|
|
@@ -290,7 +292,7 @@ export default async function aexolMcpExtension(ext) {
|
|
|
290
292
|
type: "object",
|
|
291
293
|
properties: {},
|
|
292
294
|
},
|
|
293
|
-
async execute() {
|
|
295
|
+
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
294
296
|
if (!currentBinding) {
|
|
295
297
|
return {
|
|
296
298
|
content: [{ type: "text", text: "No Studio binding found in this directory — nothing to unbind." }],
|
|
@@ -300,7 +302,7 @@ export default async function aexolMcpExtension(ext) {
|
|
|
300
302
|
const displayName = currentBinding.name ?? currentBinding.projectId;
|
|
301
303
|
const projectId = currentBinding.projectId;
|
|
302
304
|
try {
|
|
303
|
-
const deleted = await deleteStudioBinding();
|
|
305
|
+
const deleted = await deleteStudioBinding(ctx.cwd);
|
|
304
306
|
currentBinding = null;
|
|
305
307
|
if (deleted) {
|
|
306
308
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kanban-bridge.d.ts","sourceRoot":"","sources":["../../src/extensions/kanban-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"kanban-bridge.d.ts","sourceRoot":"","sources":["../../src/extensions/kanban-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAoC,MAAM,8BAA8B,CAAC;AA41BnG,wBAA8B,qBAAqB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCpF"}
|
|
@@ -170,6 +170,7 @@ import { getConfigFile } from "../config.js";
|
|
|
170
170
|
import { ensureAuthenticated } from "../auth-helper.js";
|
|
171
171
|
// Track whether we've already attempted reauth in this session to avoid loops
|
|
172
172
|
let _reauthAttempted = false;
|
|
173
|
+
let _studioBinding = null;
|
|
173
174
|
async function resolveKanbanConfig(explicitProjectId) {
|
|
174
175
|
const cfg = await readConfig();
|
|
175
176
|
if (!cfg) {
|
|
@@ -203,7 +204,7 @@ async function resolveKanbanConfig(explicitProjectId) {
|
|
|
203
204
|
let projectId = explicitProjectId || null;
|
|
204
205
|
if (!projectId) {
|
|
205
206
|
try {
|
|
206
|
-
const binding = await readStudioBinding();
|
|
207
|
+
const binding = _studioBinding ?? await readStudioBinding();
|
|
207
208
|
if (binding?.projectId) {
|
|
208
209
|
projectId = binding.projectId;
|
|
209
210
|
}
|
|
@@ -725,11 +726,14 @@ export default async function kanbanBridgeExtension(ext) {
|
|
|
725
726
|
}
|
|
726
727
|
}
|
|
727
728
|
// Verify config is resolvable on startup (non-fatal — tools work lazily too)
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
729
|
+
ext.on("session_start", async (_event, ctx) => {
|
|
730
|
+
_studioBinding = await readStudioBinding(ctx.cwd);
|
|
731
|
+
const cfg = await resolveKanbanConfig();
|
|
732
|
+
if (cfg) {
|
|
733
|
+
process.stderr.write(`[kanban-bridge] Registered ${registered} Kanban tool(s). Connected to project ${cfg.projectId}.\n`);
|
|
734
|
+
}
|
|
735
|
+
else {
|
|
736
|
+
process.stderr.write(`[kanban-bridge] Registered ${registered} Kanban tool(s). No project bound yet — tools will work once kanban_project_id or studio binding is available.\n`);
|
|
737
|
+
}
|
|
738
|
+
});
|
|
735
739
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/relay/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACf,MAAM,uBAAuB,CAAC;AAI/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAwCzD,OAAO,KAAK,EACV,oBAAoB,EACpB,UAAU,EACX,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C;;;GAGG;AACH,UAAU,UAAU;IAClB,KAAK,EACD,eAAe,GACf,gBAAgB,GAChB,gBAAgB,GAChB,gBAAgB,GAChB,aAAa,GACb,eAAe,GACf,0BAA0B,GAC1B,uBAAuB,GACvB,gBAAgB,GAChB,aAAa,GACb,gBAAgB,GAChB,gBAAgB,GAChB,oBAAoB,GACpB,4BAA4B,GAC5B,iBAAiB,GACjB,6BAA6B,GAC7B,cAAc,GACd,wBAAwB,GACxB,gBAAgB,GAChB,sBAAsB,GACtB,gBAAgB,GAChB,kBAAkB,GAClB,eAAe,GACf,oBAAoB,GACpB,iBAAiB,GACjB,cAAc,GACd,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,aAAa,CAAC;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gEAAgE;IAChE,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,UAAU,GAAG,IAAI,CA0JnB;AAMD;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,6FAA6F;IAC7F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uGAAuG;IACvG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;IACjD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAiD5B;
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/relay/dispatcher.ts"],"names":[],"mappings":"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"}
|
package/dist/relay/dispatcher.js
CHANGED
|
@@ -358,6 +358,11 @@ async function dispatchRoute(match, body, deps) {
|
|
|
358
358
|
studioProjectId: result.studioProjectId,
|
|
359
359
|
studioProjectName: result.studioProjectName,
|
|
360
360
|
});
|
|
361
|
+
// Refresh the X-Project-Id header on active bridges so agent-session
|
|
362
|
+
// credits are attributed to the newly bound project immediately.
|
|
363
|
+
manager.reloadProjectBindings().catch((err) => {
|
|
364
|
+
logger?.error?.(`[dispatcher] reloadProjectBindings failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
365
|
+
});
|
|
361
366
|
return result;
|
|
362
367
|
}
|
|
363
368
|
case "unbind_studio": {
|
|
@@ -369,6 +374,10 @@ async function dispatchRoute(match, body, deps) {
|
|
|
369
374
|
studioProjectId: result.studioProjectId,
|
|
370
375
|
});
|
|
371
376
|
}
|
|
377
|
+
// Clear the X-Project-Id header on active bridges.
|
|
378
|
+
manager.reloadProjectBindings().catch((err) => {
|
|
379
|
+
logger?.error?.(`[dispatcher] reloadProjectBindings failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
380
|
+
});
|
|
372
381
|
return result;
|
|
373
382
|
}
|
|
374
383
|
case "get_project_observations": {
|
|
@@ -155,6 +155,12 @@ export declare class AgentBridge {
|
|
|
155
155
|
/** Current model's credit rates (from availableAgentModels), used for token_usage. */
|
|
156
156
|
private activeCreditRates;
|
|
157
157
|
private memoryPhase;
|
|
158
|
+
/**
|
|
159
|
+
* Studio project id resolved from `.aexol/aexol.jsonc` in the session cwd.
|
|
160
|
+
* Sent as the `X-Project-Id` header on every proxied LLM call so the
|
|
161
|
+
* backend can attribute agent-session credits to the bound project.
|
|
162
|
+
*/
|
|
163
|
+
private boundProjectId;
|
|
158
164
|
constructor(opts: AgentBridgeOptions);
|
|
159
165
|
/**
|
|
160
166
|
* Create the spectral session, wire up subscription, and return.
|
|
@@ -162,6 +168,18 @@ export declare class AgentBridge {
|
|
|
162
168
|
*/
|
|
163
169
|
start(): Promise<void>;
|
|
164
170
|
private proxyProviderForAllowedModel;
|
|
171
|
+
/**
|
|
172
|
+
* Re-read `.aexol/aexol.jsonc` from the session cwd and update the bound
|
|
173
|
+
* studio project id. When the binding changes, re-registers synthetic
|
|
174
|
+
* providers so the `X-Project-Id` header on subsequent LLM calls reflects
|
|
175
|
+
* the new project. Safe to call repeatedly; no-op when unchanged.
|
|
176
|
+
*/
|
|
177
|
+
private refreshProjectBinding;
|
|
178
|
+
/**
|
|
179
|
+
* Public entry point for runtime binding changes (e.g. `/agent` bind/unbind).
|
|
180
|
+
* Re-reads the binding file and updates provider headers in place.
|
|
181
|
+
*/
|
|
182
|
+
reloadProjectBinding(): Promise<void>;
|
|
165
183
|
private refreshAllowedModels;
|
|
166
184
|
/**
|
|
167
185
|
* Register one synthetic provider per upstream API shape. Anthropic models
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-bridge.d.ts","sourceRoot":"","sources":["../../src/server/agent-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAaH,OAAO,EAQL,KAAK,iBAAiB,EAEvB,MAAM,8BAA8B,CAAC;AAStC,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAYrF,OAAO,EACL,kBAAkB,IAAI,yBAAyB,EAEhD,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-bridge.d.ts","sourceRoot":"","sources":["../../src/server/agent-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -63,6 +63,7 @@ import designerExtension from "../designer/index.js";
|
|
|
63
63
|
import observationalMemory from "../memory/index.js";
|
|
64
64
|
import { OBSERVATIONAL_MEMORY_CONTEXT_CUSTOM_TYPE, OBSERVATIONAL_MEMORY_SNAPSHOT_CUSTOM_TYPE, } from "../memory/types.js";
|
|
65
65
|
import { fetchAllowedModels as defaultFetchAllowedModels, } from "../relay/models-fetch.js";
|
|
66
|
+
import { readStudioBinding } from "../studio-binding.js";
|
|
66
67
|
/**
|
|
67
68
|
* Synthetic provider names registered with spectral's `ModelRegistry`. They route
|
|
68
69
|
* 100% of inference traffic through the backend (`${backendUrl}/v1`), which
|
|
@@ -394,6 +395,12 @@ export class AgentBridge {
|
|
|
394
395
|
/** Current model's credit rates (from availableAgentModels), used for token_usage. */
|
|
395
396
|
activeCreditRates = null;
|
|
396
397
|
memoryPhase = "idle";
|
|
398
|
+
/**
|
|
399
|
+
* Studio project id resolved from `.aexol/aexol.jsonc` in the session cwd.
|
|
400
|
+
* Sent as the `X-Project-Id` header on every proxied LLM call so the
|
|
401
|
+
* backend can attribute agent-session credits to the bound project.
|
|
402
|
+
*/
|
|
403
|
+
boundProjectId = null;
|
|
397
404
|
constructor(opts) {
|
|
398
405
|
this.opts = opts;
|
|
399
406
|
}
|
|
@@ -586,6 +593,9 @@ export class AgentBridge {
|
|
|
586
593
|
// disk-based auth: this is the single path for `spectral serve`.
|
|
587
594
|
const authStorage = AuthStorage.inMemory();
|
|
588
595
|
this.modelRegistry = ModelRegistry.inMemory(authStorage);
|
|
596
|
+
// Resolve the studio project binding before registering synthetic
|
|
597
|
+
// providers so the `X-Project-Id` header is present from the first call.
|
|
598
|
+
await this.refreshProjectBinding();
|
|
589
599
|
let allowedModels;
|
|
590
600
|
try {
|
|
591
601
|
allowedModels = await this.refreshAllowedModels();
|
|
@@ -659,6 +669,35 @@ export class AgentBridge {
|
|
|
659
669
|
}
|
|
660
670
|
return SPECTRAL_PROXY_OPENAI;
|
|
661
671
|
}
|
|
672
|
+
/**
|
|
673
|
+
* Re-read `.aexol/aexol.jsonc` from the session cwd and update the bound
|
|
674
|
+
* studio project id. When the binding changes, re-registers synthetic
|
|
675
|
+
* providers so the `X-Project-Id` header on subsequent LLM calls reflects
|
|
676
|
+
* the new project. Safe to call repeatedly; no-op when unchanged.
|
|
677
|
+
*/
|
|
678
|
+
async refreshProjectBinding() {
|
|
679
|
+
let nextId = null;
|
|
680
|
+
try {
|
|
681
|
+
const binding = await readStudioBinding(this.opts.cwd);
|
|
682
|
+
nextId = binding?.projectId ?? null;
|
|
683
|
+
}
|
|
684
|
+
catch {
|
|
685
|
+
nextId = null;
|
|
686
|
+
}
|
|
687
|
+
if (nextId === this.boundProjectId)
|
|
688
|
+
return;
|
|
689
|
+
this.boundProjectId = nextId;
|
|
690
|
+
if (this.allowedModels && this.modelRegistry) {
|
|
691
|
+
this.registerSyntheticProviders(this.allowedModels);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Public entry point for runtime binding changes (e.g. `/agent` bind/unbind).
|
|
696
|
+
* Re-reads the binding file and updates provider headers in place.
|
|
697
|
+
*/
|
|
698
|
+
async reloadProjectBinding() {
|
|
699
|
+
await this.refreshProjectBinding();
|
|
700
|
+
}
|
|
662
701
|
async refreshAllowedModels(opts) {
|
|
663
702
|
if (!this.modelRegistry) {
|
|
664
703
|
throw new Error("AgentBridge model registry unavailable");
|
|
@@ -710,6 +749,11 @@ export class AgentBridge {
|
|
|
710
749
|
if (!this.modelRegistry)
|
|
711
750
|
return;
|
|
712
751
|
const baseUrl = `${this.opts.backendUrl.replace(/\/$/, "")}/v1`;
|
|
752
|
+
// Inject the bound studio project id as X-Project-Id on every proxied
|
|
753
|
+
// LLM call so the backend attributes agent-session credits to the project.
|
|
754
|
+
const providerHeaders = this.boundProjectId
|
|
755
|
+
? { "X-Project-Id": this.boundProjectId }
|
|
756
|
+
: undefined;
|
|
713
757
|
const anthropicModels = allowedModels.filter((m) => m.provider === "anthropic");
|
|
714
758
|
const openaiCompatModels = allowedModels.filter((m) => m.provider !== "anthropic" && m.provider !== "built-in");
|
|
715
759
|
if (anthropicModels.length > 0) {
|
|
@@ -717,6 +761,7 @@ export class AgentBridge {
|
|
|
717
761
|
baseUrl,
|
|
718
762
|
apiKey: this.opts.machineJwt,
|
|
719
763
|
authHeader: true,
|
|
764
|
+
headers: providerHeaders,
|
|
720
765
|
api: "anthropic-messages",
|
|
721
766
|
models: anthropicModels.map((m) => {
|
|
722
767
|
return {
|
|
@@ -745,6 +790,7 @@ export class AgentBridge {
|
|
|
745
790
|
baseUrl,
|
|
746
791
|
apiKey: this.opts.machineJwt,
|
|
747
792
|
authHeader: true,
|
|
793
|
+
headers: providerHeaders,
|
|
748
794
|
api: "openai-completions",
|
|
749
795
|
models: openaiCompatModels.map((m) => {
|
|
750
796
|
return {
|
|
@@ -777,6 +823,7 @@ export class AgentBridge {
|
|
|
777
823
|
baseUrl,
|
|
778
824
|
apiKey: this.opts.machineJwt,
|
|
779
825
|
authHeader: true,
|
|
826
|
+
headers: providerHeaders,
|
|
780
827
|
api: "openai-completions",
|
|
781
828
|
models: userModelEntries.map((m) => {
|
|
782
829
|
return {
|
|
@@ -78,6 +78,7 @@ export interface BridgeLike {
|
|
|
78
78
|
* surfaced an error (the manager will then drop the prompt).
|
|
79
79
|
*/
|
|
80
80
|
setModel?(modelId: string | null | undefined): Promise<boolean>;
|
|
81
|
+
reloadProjectBinding?(): Promise<void>;
|
|
81
82
|
/**
|
|
82
83
|
* Return the modelId of the first available model from the backend
|
|
83
84
|
* whitelist (preserving backend sortOrder). Used as defense-in-depth
|
|
@@ -225,6 +226,13 @@ export declare class SessionStreamManager {
|
|
|
225
226
|
* render a yellow pulsating dot next to active sessions/projects.
|
|
226
227
|
*/
|
|
227
228
|
getActiveTurnSessionIds(): Set<string>;
|
|
229
|
+
/**
|
|
230
|
+
* Re-read `.aexol/aexol.jsonc` on every active bridge so the `X-Project-Id`
|
|
231
|
+
* header on proxied LLM calls reflects the latest studio binding. Called
|
|
232
|
+
* after `/agent` bind/unbind so agent-session credits are attributed to the
|
|
233
|
+
* correct project without restarting the session.
|
|
234
|
+
*/
|
|
235
|
+
reloadProjectBindings(): Promise<void>;
|
|
228
236
|
getSessionMemoryStatus(sessionId: string): SessionMemoryStatus;
|
|
229
237
|
getSessionMemoryDetails(sessionId: string): WireSessionMemoryDetails;
|
|
230
238
|
compactSession(sessionId: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-stream.d.ts","sourceRoot":"","sources":["../../src/server/session-stream.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"session-stream.d.ts","sourceRoot":"","sources":["../../src/server/session-stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -320,6 +320,21 @@ export class SessionStreamManager {
|
|
|
320
320
|
}
|
|
321
321
|
return ids;
|
|
322
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Re-read `.aexol/aexol.jsonc` on every active bridge so the `X-Project-Id`
|
|
325
|
+
* header on proxied LLM calls reflects the latest studio binding. Called
|
|
326
|
+
* after `/agent` bind/unbind so agent-session credits are attributed to the
|
|
327
|
+
* correct project without restarting the session.
|
|
328
|
+
*/
|
|
329
|
+
async reloadProjectBindings() {
|
|
330
|
+
const promises = [];
|
|
331
|
+
for (const stream of this.streams.values()) {
|
|
332
|
+
if (stream.bridge.reloadProjectBinding) {
|
|
333
|
+
promises.push(stream.bridge.reloadProjectBinding());
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
await Promise.all(promises);
|
|
337
|
+
}
|
|
323
338
|
getSessionMemoryStatus(sessionId) {
|
|
324
339
|
const detail = this.store.getSession(sessionId);
|
|
325
340
|
if (!detail)
|
package/dist/studio-binding.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export interface StudioBinding {
|
|
|
11
11
|
$schema?: string;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
* Strip JSONC comments (//
|
|
14
|
+
* Strip JSONC comments (line // and block comments) from raw source text.
|
|
15
15
|
* Kept simple — the binding file shape is well-known.
|
|
16
16
|
*/
|
|
17
17
|
export declare function stripJsoncComments(raw: string): string;
|
|
@@ -20,30 +20,27 @@ export declare function stripJsoncComments(raw: string): string;
|
|
|
20
20
|
* Returns `null` when no binding file exists (file missing, or directory
|
|
21
21
|
* absent — treated the same way: not bound).
|
|
22
22
|
*/
|
|
23
|
-
export declare function readStudioBinding(): Promise<StudioBinding | null>;
|
|
23
|
+
export declare function readStudioBinding(cwd?: string): Promise<StudioBinding | null>;
|
|
24
24
|
/**
|
|
25
|
-
* Read
|
|
26
|
-
* Works like `readStudioBinding()` but reads from `projectPath/.aexol/aexol.jsonc`
|
|
27
|
-
* instead of `process.cwd()`.
|
|
25
|
+
* Read a Studio binding from an explicit project directory.
|
|
28
26
|
*/
|
|
29
27
|
export declare function readStudioBindingAt(projectPath: string): Promise<StudioBinding | null>;
|
|
30
28
|
/**
|
|
31
|
-
*
|
|
29
|
+
* Write (create or overwrite) the local Studio binding file in the current
|
|
30
|
+
* working directory (or under the provided cwd).
|
|
32
31
|
*/
|
|
33
|
-
export declare function writeStudioBinding(binding: StudioBinding): Promise<void>;
|
|
32
|
+
export declare function writeStudioBinding(binding: StudioBinding, cwd?: string): Promise<void>;
|
|
34
33
|
/**
|
|
35
|
-
*
|
|
36
|
-
* under that directory). Uses the same format as `writeStudioBinding`.
|
|
34
|
+
* Write a Studio binding under an explicit project directory.
|
|
37
35
|
*/
|
|
38
36
|
export declare function writeStudioBindingAt(projectPath: string, binding: StudioBinding): Promise<void>;
|
|
39
37
|
/**
|
|
40
|
-
*
|
|
41
|
-
* Returns `true`
|
|
38
|
+
* Delete the local Studio binding file in the current working directory
|
|
39
|
+
* (or under the provided cwd). Returns `true` if a file was actually removed.
|
|
42
40
|
*/
|
|
43
|
-
export declare function deleteStudioBinding(): Promise<boolean>;
|
|
41
|
+
export declare function deleteStudioBinding(cwd?: string): Promise<boolean>;
|
|
44
42
|
/**
|
|
45
|
-
*
|
|
46
|
-
* Returns `true` when the file existed and was deleted, `false` otherwise (no-op).
|
|
43
|
+
* Delete the Studio binding file under an explicit project directory.
|
|
47
44
|
*/
|
|
48
45
|
export declare function deleteStudioBindingAt(projectPath: string): Promise<boolean>;
|
|
49
46
|
//# sourceMappingURL=studio-binding.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"studio-binding.d.ts","sourceRoot":"","sources":["../src/studio-binding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAaD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAItD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"studio-binding.d.ts","sourceRoot":"","sources":["../src/studio-binding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAaD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAItD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAU/B;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAY/B;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,aAAa,EACtB,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASxE;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASjF"}
|
package/dist/studio-binding.js
CHANGED
|
@@ -9,14 +9,14 @@ import { constants } from "node:fs";
|
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
const BINDING_DIR = ".aexol";
|
|
11
11
|
const BINDING_FILE = "aexol.jsonc";
|
|
12
|
-
function bindingDir() {
|
|
13
|
-
return join(process.cwd(), BINDING_DIR);
|
|
12
|
+
function bindingDir(cwd) {
|
|
13
|
+
return join(cwd ?? process.cwd(), BINDING_DIR);
|
|
14
14
|
}
|
|
15
|
-
function bindingPath() {
|
|
16
|
-
return join(bindingDir(), BINDING_FILE);
|
|
15
|
+
function bindingPath(cwd) {
|
|
16
|
+
return join(bindingDir(cwd), BINDING_FILE);
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
* Strip JSONC comments (//
|
|
19
|
+
* Strip JSONC comments (line // and block comments) from raw source text.
|
|
20
20
|
* Kept simple — the binding file shape is well-known.
|
|
21
21
|
*/
|
|
22
22
|
export function stripJsoncComments(raw) {
|
|
@@ -29,9 +29,9 @@ export function stripJsoncComments(raw) {
|
|
|
29
29
|
* Returns `null` when no binding file exists (file missing, or directory
|
|
30
30
|
* absent — treated the same way: not bound).
|
|
31
31
|
*/
|
|
32
|
-
export async function readStudioBinding() {
|
|
32
|
+
export async function readStudioBinding(cwd) {
|
|
33
33
|
try {
|
|
34
|
-
const raw = await readFile(bindingPath(), "utf8");
|
|
34
|
+
const raw = await readFile(bindingPath(cwd), "utf8");
|
|
35
35
|
return JSON.parse(stripJsoncComments(raw));
|
|
36
36
|
}
|
|
37
37
|
catch (err) {
|
|
@@ -43,9 +43,7 @@ export async function readStudioBinding() {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* Read
|
|
47
|
-
* Works like `readStudioBinding()` but reads from `projectPath/.aexol/aexol.jsonc`
|
|
48
|
-
* instead of `process.cwd()`.
|
|
46
|
+
* Read a Studio binding from an explicit project directory.
|
|
49
47
|
*/
|
|
50
48
|
export async function readStudioBindingAt(projectPath) {
|
|
51
49
|
try {
|
|
@@ -54,17 +52,17 @@ export async function readStudioBindingAt(projectPath) {
|
|
|
54
52
|
}
|
|
55
53
|
catch (err) {
|
|
56
54
|
const code = err.code;
|
|
57
|
-
// Missing file or missing directory → not bound.
|
|
58
55
|
if (code === "ENOENT" || code === "ENOTDIR")
|
|
59
56
|
return null;
|
|
60
57
|
throw err;
|
|
61
58
|
}
|
|
62
59
|
}
|
|
63
60
|
/**
|
|
64
|
-
*
|
|
61
|
+
* Write (create or overwrite) the local Studio binding file in the current
|
|
62
|
+
* working directory (or under the provided cwd).
|
|
65
63
|
*/
|
|
66
|
-
export async function writeStudioBinding(binding) {
|
|
67
|
-
const dir = bindingDir();
|
|
64
|
+
export async function writeStudioBinding(binding, cwd) {
|
|
65
|
+
const dir = bindingDir(cwd);
|
|
68
66
|
try {
|
|
69
67
|
await access(dir, constants.F_OK);
|
|
70
68
|
}
|
|
@@ -77,11 +75,10 @@ export async function writeStudioBinding(binding) {
|
|
|
77
75
|
`\n` +
|
|
78
76
|
JSON.stringify(binding, null, 2) +
|
|
79
77
|
"\n";
|
|
80
|
-
await writeFile(bindingPath(), content, "utf8");
|
|
78
|
+
await writeFile(bindingPath(cwd), content, "utf8");
|
|
81
79
|
}
|
|
82
80
|
/**
|
|
83
|
-
*
|
|
84
|
-
* under that directory). Uses the same format as `writeStudioBinding`.
|
|
81
|
+
* Write a Studio binding under an explicit project directory.
|
|
85
82
|
*/
|
|
86
83
|
export async function writeStudioBindingAt(projectPath, binding) {
|
|
87
84
|
const dir = join(projectPath, BINDING_DIR);
|
|
@@ -100,12 +97,12 @@ export async function writeStudioBindingAt(projectPath, binding) {
|
|
|
100
97
|
await writeFile(join(dir, BINDING_FILE), content, "utf8");
|
|
101
98
|
}
|
|
102
99
|
/**
|
|
103
|
-
*
|
|
104
|
-
* Returns `true`
|
|
100
|
+
* Delete the local Studio binding file in the current working directory
|
|
101
|
+
* (or under the provided cwd). Returns `true` if a file was actually removed.
|
|
105
102
|
*/
|
|
106
|
-
export async function deleteStudioBinding() {
|
|
103
|
+
export async function deleteStudioBinding(cwd) {
|
|
107
104
|
try {
|
|
108
|
-
await unlink(bindingPath());
|
|
105
|
+
await unlink(bindingPath(cwd));
|
|
109
106
|
return true;
|
|
110
107
|
}
|
|
111
108
|
catch (err) {
|
|
@@ -116,8 +113,7 @@ export async function deleteStudioBinding() {
|
|
|
116
113
|
}
|
|
117
114
|
}
|
|
118
115
|
/**
|
|
119
|
-
*
|
|
120
|
-
* Returns `true` when the file existed and was deleted, `false` otherwise (no-op).
|
|
116
|
+
* Delete the Studio binding file under an explicit project directory.
|
|
121
117
|
*/
|
|
122
118
|
export async function deleteStudioBindingAt(projectPath) {
|
|
123
119
|
try {
|