@lamplitisles/codex-for-love 0.2.0 → 0.3.0
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/package.json +1 -1
- package/vendor/IMPORTS.md +3 -2
- package/vendor/build/_app/immutable/assets/0.D3rCUG9u.css +2 -0
- package/vendor/build/_app/immutable/chunks/utqCDLTs.js +1 -0
- package/vendor/build/_app/immutable/entry/{app.BP5g3Nlw.js → app.BbmlpP2X.js} +2 -2
- package/vendor/build/_app/immutable/entry/start.BmMe00-v.js +1 -0
- package/vendor/build/_app/immutable/nodes/{1.Da3Wny27.js → 1.DXp8K3IS.js} +1 -1
- package/vendor/build/_app/immutable/nodes/{2.B57CsN6q.js → 2.DVm7T6dW.js} +38 -38
- package/vendor/build/_app/version.json +1 -1
- package/vendor/build/index.html +8 -8
- package/vendor/config.example.toml +6 -8
- package/vendor/runtime/cli.mjs +54 -170
- package/vendor/runtime/companion-mcp.mjs +1076 -10
- package/vendor/build/_app/immutable/assets/0.CGGimnj2.css +0 -2
- package/vendor/build/_app/immutable/chunks/C1lTIQVt.js +0 -1
- package/vendor/build/_app/immutable/entry/start.SkCiAosv.js +0 -1
- /package/vendor/build/_app/immutable/nodes/{0.C1vi8tBo.js → 0.Wk08-krq.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"
|
|
1
|
+
{"version":"1789539874385"}
|
package/vendor/build/index.html
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html lang="en" data-theme="sticker-messenger">
|
|
3
|
-
<head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><script>(function(){try{var appearance=localStorage.getItem('lamplitisles.companion.appearance');var language=localStorage.getItem('lamplitisles.companion.language');var systemDark=matchMedia('(prefers-color-scheme: dark)').matches;var dark=appearance==='dark'||(appearance!=='light'&&systemDark);document.documentElement.dataset.theme=dark?'night-voyage':'sticker-messenger';document.documentElement.lang=language==='zh'?'zh-Hans':'en'}catch(_){var systemDark=matchMedia('(prefers-color-scheme: dark)').matches;document.documentElement.dataset.theme=systemDark?'night-voyage':'sticker-messenger'}})();</script><link href="/_app/immutable/entry/start.
|
|
4
|
-
<link href="/_app/immutable/chunks/
|
|
3
|
+
<head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><script>(function(){try{var appearance=localStorage.getItem('lamplitisles.companion.appearance');var language=localStorage.getItem('lamplitisles.companion.language');var systemDark=matchMedia('(prefers-color-scheme: dark)').matches;var dark=appearance==='dark'||(appearance!=='light'&&systemDark);document.documentElement.dataset.theme=dark?'night-voyage':'sticker-messenger';document.documentElement.lang=language==='zh'?'zh-Hans':'en'}catch(_){var systemDark=matchMedia('(prefers-color-scheme: dark)').matches;document.documentElement.dataset.theme=systemDark?'night-voyage':'sticker-messenger'}})();</script><link href="/_app/immutable/entry/start.BmMe00-v.js" rel="modulepreload">
|
|
4
|
+
<link href="/_app/immutable/chunks/utqCDLTs.js" rel="modulepreload">
|
|
5
5
|
<link href="/_app/immutable/chunks/DtqGwW3l.js" rel="modulepreload">
|
|
6
|
-
<link href="/_app/immutable/entry/app.
|
|
6
|
+
<link href="/_app/immutable/entry/app.BbmlpP2X.js" rel="modulepreload">
|
|
7
7
|
<link href="/_app/immutable/chunks/xihTtKlq.js" rel="modulepreload">
|
|
8
|
-
<link href="/_app/immutable/nodes/0.
|
|
8
|
+
<link href="/_app/immutable/nodes/0.Wk08-krq.js" rel="modulepreload">
|
|
9
9
|
|
|
10
|
-
<link href="/_app/immutable/assets/0.
|
|
10
|
+
<link href="/_app/immutable/assets/0.D3rCUG9u.css" rel="stylesheet"></head>
|
|
11
11
|
<body data-sveltekit-preload-data="hover"><div style="display: contents">
|
|
12
12
|
<script>
|
|
13
13
|
{
|
|
14
|
-
|
|
14
|
+
__sveltekit_uz4ce0 = {
|
|
15
15
|
base: ""
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
const element = document.currentScript.parentElement;
|
|
19
19
|
|
|
20
20
|
Promise.all([
|
|
21
|
-
import("/_app/immutable/entry/start.
|
|
22
|
-
import("/_app/immutable/entry/app.
|
|
21
|
+
import("/_app/immutable/entry/start.BmMe00-v.js"),
|
|
22
|
+
import("/_app/immutable/entry/app.BbmlpP2X.js")
|
|
23
23
|
]).then(([kit, app]) => {
|
|
24
24
|
kit.start(app, element);
|
|
25
25
|
});
|
|
@@ -21,11 +21,9 @@ model = "gpt-5.6-luna"
|
|
|
21
21
|
# local_compaction = true
|
|
22
22
|
# home = "/path/to/a/Codex-home" # omit to use the existing Codex login
|
|
23
23
|
|
|
24
|
-
# Optional DashScope STT and
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
#
|
|
30
|
-
# model = "qwen3-tts-flash"
|
|
31
|
-
# voice = "Cherry"
|
|
24
|
+
# Optional DashScope STT and tool-delivered Voice messages.
|
|
25
|
+
[speech]
|
|
26
|
+
[speech.tts]
|
|
27
|
+
provider = "minimax" # or "alibaba" (speech credential), "bytedance" (tts credential)
|
|
28
|
+
voice = "Chinese (Mandarin)_Soft_Girl"
|
|
29
|
+
# MiniMax requires the operator-installed, authenticated `mmx` CLI. No MiniMax secret belongs in this file.
|
package/vendor/runtime/cli.mjs
CHANGED
|
@@ -16,6 +16,8 @@ import { createConnection, isIP } from "net";
|
|
|
16
16
|
import * as fs from "node:fs";
|
|
17
17
|
import { constants, createReadStream } from "node:fs";
|
|
18
18
|
import { DatabaseSync } from "node:sqlite";
|
|
19
|
+
import { execFile } from "node:child_process";
|
|
20
|
+
import { promisify } from "node:util";
|
|
19
21
|
import { createServer } from "node:http";
|
|
20
22
|
import * as qs from "node:querystring";
|
|
21
23
|
//#region \0rolldown/runtime.js
|
|
@@ -5299,7 +5301,7 @@ const parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
|
5299
5301
|
const safeParse = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
5300
5302
|
const safeParseAsync = /* @__PURE__ */ _safeParseAsync(ZodRealError);
|
|
5301
5303
|
const encode = /* @__PURE__ */ _encode(ZodRealError);
|
|
5302
|
-
const decode
|
|
5304
|
+
const decode = /* @__PURE__ */ _decode(ZodRealError);
|
|
5303
5305
|
const encodeAsync = /* @__PURE__ */ _encodeAsync(ZodRealError);
|
|
5304
5306
|
const decodeAsync = /* @__PURE__ */ _decodeAsync(ZodRealError);
|
|
5305
5307
|
const safeEncode = /* @__PURE__ */ _safeEncode(ZodRealError);
|
|
@@ -5453,7 +5455,7 @@ const ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => {
|
|
|
5453
5455
|
return encode(this, data, params, { callee: _encode });
|
|
5454
5456
|
},
|
|
5455
5457
|
decode: function _decode(data, params) {
|
|
5456
|
-
return decode
|
|
5458
|
+
return decode(this, data, params, { callee: _decode });
|
|
5457
5459
|
},
|
|
5458
5460
|
encodeAsync: async function _encodeAsync(data, params) {
|
|
5459
5461
|
return await encodeAsync(this, data, params, { callee: _encodeAsync });
|
|
@@ -6196,10 +6198,12 @@ const schema = object({
|
|
|
6196
6198
|
speech: object({
|
|
6197
6199
|
endpoint: url().default("https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"),
|
|
6198
6200
|
tts: object({
|
|
6199
|
-
provider: _enum([
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6201
|
+
provider: _enum([
|
|
6202
|
+
"minimax",
|
|
6203
|
+
"alibaba",
|
|
6204
|
+
"bytedance"
|
|
6205
|
+
]),
|
|
6206
|
+
voice: string().min(1)
|
|
6203
6207
|
}).strict().optional()
|
|
6204
6208
|
}).strict().optional()
|
|
6205
6209
|
}).strict();
|
|
@@ -6208,6 +6212,7 @@ async function loadConfig(path) {
|
|
|
6208
6212
|
const base = dirname(resolve(path));
|
|
6209
6213
|
return {
|
|
6210
6214
|
...config,
|
|
6215
|
+
configPath: resolve(path),
|
|
6211
6216
|
state: resolve(base, config.state),
|
|
6212
6217
|
persona: resolve(base, config.persona),
|
|
6213
6218
|
workspace: resolve(base, config.workspace ?? `${config.state}/workspace`),
|
|
@@ -6222,7 +6227,7 @@ async function loadConfig(path) {
|
|
|
6222
6227
|
}
|
|
6223
6228
|
};
|
|
6224
6229
|
}
|
|
6225
|
-
/**
|
|
6230
|
+
/** Alibaba STT/TTS reuses speech; ByteDance TTS keeps its separate secret. */
|
|
6226
6231
|
const credentialSchema = object({
|
|
6227
6232
|
speech: string().min(1).optional(),
|
|
6228
6233
|
tts: string().min(1).optional()
|
|
@@ -62651,12 +62656,16 @@ function sameValue(left, right) {
|
|
|
62651
62656
|
return JSON.stringify(left) === JSON.stringify(right);
|
|
62652
62657
|
}
|
|
62653
62658
|
/** Keep only CFL's installation-specific Companion endpoint current. */
|
|
62654
|
-
function ensureCompanionMcp(config, workspace) {
|
|
62659
|
+
function ensureCompanionMcp(config, workspace, partnerConfigPath) {
|
|
62655
62660
|
const servers = isRecord$1(config.mcp_servers) ? config.mcp_servers : {};
|
|
62656
62661
|
let changed = !isRecord$1(config.mcp_servers);
|
|
62657
62662
|
const required = {
|
|
62658
62663
|
command: process.execPath,
|
|
62659
|
-
args: [
|
|
62664
|
+
args: [
|
|
62665
|
+
fileURLToPath(new URL(`./${companionMcpFileName}`, import.meta.url)),
|
|
62666
|
+
resolve(workspace),
|
|
62667
|
+
...partnerConfigPath ? [resolve(partnerConfigPath)] : []
|
|
62668
|
+
]
|
|
62660
62669
|
};
|
|
62661
62670
|
const companion = isRecord$1(servers.companion) ? servers.companion : {};
|
|
62662
62671
|
for (const [key, value] of Object.entries(required)) if (!sameValue(companion[key], value)) {
|
|
@@ -62671,7 +62680,7 @@ function ensureCompanionMcp(config, workspace) {
|
|
|
62671
62680
|
return changed;
|
|
62672
62681
|
}
|
|
62673
62682
|
/** Add project-owned hooks and the bundled Companion MCP while preserving config. */
|
|
62674
|
-
async function ensureHookDeclaration(workspace, contextPath) {
|
|
62683
|
+
async function ensureHookDeclaration(workspace, contextPath, partnerConfigPath) {
|
|
62675
62684
|
const configPath = join(resolve(workspace), ".codex", "config.toml");
|
|
62676
62685
|
const command = hookCommand(contextPath);
|
|
62677
62686
|
await mkdir(dirname(configPath), {
|
|
@@ -62688,7 +62697,7 @@ async function ensureHookDeclaration(workspace, contextPath) {
|
|
|
62688
62697
|
}
|
|
62689
62698
|
const hooks = isRecord$1(config.hooks) ? config.hooks : {};
|
|
62690
62699
|
const sessionStart = Array.isArray(hooks.SessionStart) ? hooks.SessionStart : [];
|
|
62691
|
-
let changed = ensureCompanionMcp(config, workspace);
|
|
62700
|
+
let changed = ensureCompanionMcp(config, workspace, partnerConfigPath);
|
|
62692
62701
|
let own = false;
|
|
62693
62702
|
const normalizedGroups = sessionStart.map((group) => {
|
|
62694
62703
|
if (!isRecord$1(group) || !Array.isArray(group.hooks)) return group;
|
|
@@ -64892,140 +64901,8 @@ function normalizeVoiceExpression(value) {
|
|
|
64892
64901
|
if (!isVoiceExpression(value)) return void 0;
|
|
64893
64902
|
return value.trim().toLowerCase();
|
|
64894
64903
|
}
|
|
64895
|
-
|
|
64896
|
-
|
|
64897
|
-
const MAX_AUDIO_BYTES = 10485760;
|
|
64898
|
-
const MAX_RESPONSE_BYTES = Math.ceil(MAX_AUDIO_BYTES / 3) * 4 + 65536;
|
|
64899
|
-
const pending = /* @__PURE__ */ new Map();
|
|
64900
|
-
const BTD_ENDPOINT = "https://openspeech.bytedance.com/api/v3/tts/unidirectional/sse";
|
|
64901
|
-
function decode(value) {
|
|
64902
|
-
const source = value.replace(/^data:[^;,]+;base64,/u, "");
|
|
64903
|
-
if (!/^[A-Za-z0-9+/]*={0,2}$/u.test(source) || source.length % 4 === 1) return;
|
|
64904
|
-
return new Uint8Array(Buffer.from(source, "base64"));
|
|
64905
|
-
}
|
|
64906
|
-
async function bounded$1(response, limit) {
|
|
64907
|
-
if (!response.body) throw new Error("Missing provider response");
|
|
64908
|
-
const parts = [];
|
|
64909
|
-
let total = 0;
|
|
64910
|
-
for await (const part of response.body) {
|
|
64911
|
-
total += part.byteLength;
|
|
64912
|
-
if (total > limit) throw new Error("Provider response too large");
|
|
64913
|
-
parts.push(part);
|
|
64914
|
-
}
|
|
64915
|
-
return Buffer.concat(parts);
|
|
64916
|
-
}
|
|
64917
|
-
async function provider(options) {
|
|
64918
|
-
const init = options.provider === "alibaba" ? {
|
|
64919
|
-
method: "POST",
|
|
64920
|
-
signal: options.signal,
|
|
64921
|
-
headers: {
|
|
64922
|
-
authorization: `Bearer ${options.credential}`,
|
|
64923
|
-
"content-type": "application/json"
|
|
64924
|
-
},
|
|
64925
|
-
body: JSON.stringify({
|
|
64926
|
-
model: options.model,
|
|
64927
|
-
input: {
|
|
64928
|
-
text: options.text,
|
|
64929
|
-
voice: options.voice,
|
|
64930
|
-
language_type: "Chinese"
|
|
64931
|
-
},
|
|
64932
|
-
parameters: { format: "mp3" },
|
|
64933
|
-
stream: false
|
|
64934
|
-
})
|
|
64935
|
-
} : {
|
|
64936
|
-
method: "POST",
|
|
64937
|
-
signal: options.signal,
|
|
64938
|
-
headers: {
|
|
64939
|
-
accept: "text/event-stream",
|
|
64940
|
-
"content-type": "application/json",
|
|
64941
|
-
"X-Api-Key": options.credential,
|
|
64942
|
-
"X-Api-Resource-Id": options.model
|
|
64943
|
-
},
|
|
64944
|
-
body: JSON.stringify({
|
|
64945
|
-
user: { uid: "dsh-speech" },
|
|
64946
|
-
req_params: {
|
|
64947
|
-
text: options.text,
|
|
64948
|
-
speaker: options.voice,
|
|
64949
|
-
audio_params: {
|
|
64950
|
-
format: "mp3",
|
|
64951
|
-
sample_rate: 24e3
|
|
64952
|
-
}
|
|
64953
|
-
}
|
|
64954
|
-
})
|
|
64955
|
-
};
|
|
64956
|
-
const response = await options.fetchImpl(options.provider === "bytedance" ? BTD_ENDPOINT : options.endpoint, init);
|
|
64957
|
-
if (!response.ok) throw new Error("Speech provider rejected the request");
|
|
64958
|
-
const raw = await bounded$1(response, MAX_RESPONSE_BYTES);
|
|
64959
|
-
if (options.provider === "alibaba") {
|
|
64960
|
-
const audio = JSON.parse(new TextDecoder().decode(raw))?.output?.audio;
|
|
64961
|
-
let bytes = audio?.data ? decode(audio.data) : void 0;
|
|
64962
|
-
if (!bytes && audio?.url) {
|
|
64963
|
-
const r = await options.fetchImpl(audio.url, { signal: options.signal });
|
|
64964
|
-
if (!r.ok) throw new Error("Invalid provider audio");
|
|
64965
|
-
bytes = await bounded$1(r, MAX_AUDIO_BYTES);
|
|
64966
|
-
}
|
|
64967
|
-
if (!bytes?.byteLength || bytes.byteLength > MAX_AUDIO_BYTES) throw new Error("Invalid provider audio");
|
|
64968
|
-
return bytes;
|
|
64969
|
-
}
|
|
64970
|
-
const chunks = [];
|
|
64971
|
-
let total = 0;
|
|
64972
|
-
for (const line of new TextDecoder().decode(raw).split(/\r?\n/u)) {
|
|
64973
|
-
if (!line.trim() || line.startsWith("event:")) continue;
|
|
64974
|
-
if (!line.startsWith("data:")) throw new Error("Invalid provider response");
|
|
64975
|
-
const frame = JSON.parse(line.slice(5));
|
|
64976
|
-
if (frame.code === 0 && frame.data) {
|
|
64977
|
-
const b = decode(frame.data);
|
|
64978
|
-
if (!b || (total += b.byteLength) > MAX_AUDIO_BYTES) throw new Error("Invalid provider audio");
|
|
64979
|
-
chunks.push(b);
|
|
64980
|
-
} else if (frame.code !== 0 && frame.code !== 2e7) throw new Error("Speech provider rejected the request");
|
|
64981
|
-
}
|
|
64982
|
-
const bytes = Buffer.concat(chunks);
|
|
64983
|
-
if (!bytes.byteLength) throw new Error("Invalid provider audio");
|
|
64984
|
-
return bytes;
|
|
64985
|
-
}
|
|
64986
|
-
async function synthesizeSpeech(options) {
|
|
64987
|
-
const text = options.text.replace(/[\s\u00a0]+/gu, " ").trim();
|
|
64988
|
-
if (!text || Array.from(text).length > 240) throw new Error("Invalid speech passage");
|
|
64989
|
-
const key = createHash("sha256").update(JSON.stringify([
|
|
64990
|
-
2,
|
|
64991
|
-
options.provider,
|
|
64992
|
-
options.model,
|
|
64993
|
-
options.voice,
|
|
64994
|
-
text
|
|
64995
|
-
])).digest("hex");
|
|
64996
|
-
const path = join(options.audioDir, `${key}.mp3`);
|
|
64997
|
-
try {
|
|
64998
|
-
if ((await readFile(path)).byteLength) return key;
|
|
64999
|
-
} catch {}
|
|
65000
|
-
if (pending.has(path)) return pending.get(path);
|
|
65001
|
-
const task = (async () => {
|
|
65002
|
-
const signal = AbortSignal.any([options.signal ?? new AbortController().signal, AbortSignal.timeout(6e4)]);
|
|
65003
|
-
const bytes = await provider({
|
|
65004
|
-
...options,
|
|
65005
|
-
text,
|
|
65006
|
-
signal,
|
|
65007
|
-
fetchImpl: options.fetchImpl ?? fetch
|
|
65008
|
-
});
|
|
65009
|
-
await mkdir(options.audioDir, { recursive: true });
|
|
65010
|
-
const temp = join(options.audioDir, `.${randomUUID()}.tmp`);
|
|
65011
|
-
try {
|
|
65012
|
-
await writeFile(temp, bytes, {
|
|
65013
|
-
mode: 384,
|
|
65014
|
-
flag: "wx"
|
|
65015
|
-
});
|
|
65016
|
-
await rename(temp, path);
|
|
65017
|
-
} finally {
|
|
65018
|
-
await unlink(temp).catch(() => void 0);
|
|
65019
|
-
}
|
|
65020
|
-
return key;
|
|
65021
|
-
})();
|
|
65022
|
-
pending.set(path, task);
|
|
65023
|
-
try {
|
|
65024
|
-
return await task;
|
|
65025
|
-
} finally {
|
|
65026
|
-
if (pending.get(path) === task) pending.delete(path);
|
|
65027
|
-
}
|
|
65028
|
-
}
|
|
64904
|
+
Math.ceil(10485760 / 3) * 4 + 65536;
|
|
64905
|
+
promisify(execFile);
|
|
65029
64906
|
/** Qwen short-audio STT protocol adapted from dsh-speech; no synthesis path. */
|
|
65030
64907
|
async function transcribeAudio(endpoint, credential, data, mediaType, signal, fetchImpl = fetch) {
|
|
65031
64908
|
const normalized = normalizeVoiceMediaType(mediaType);
|
|
@@ -65169,7 +65046,7 @@ function visibleHistoryPage(messages, results, before) {
|
|
|
65169
65046
|
for (; index >= 0; index -= 1) {
|
|
65170
65047
|
const message = candidates[index];
|
|
65171
65048
|
const result = resultByOwner.get(message.id);
|
|
65172
|
-
const units = 1 + (result ? result.answers.length + result.generatedIds.length + (result.error || [
|
|
65049
|
+
const units = 1 + (result ? result.answers.length + result.generatedIds.length + result.voiceIds.length + (result.error || [
|
|
65173
65050
|
"failed",
|
|
65174
65051
|
"interrupted",
|
|
65175
65052
|
"cancelled"
|
|
@@ -65256,6 +65133,22 @@ function answersFromTurn(turn) {
|
|
|
65256
65133
|
if (!turn?.items) return [];
|
|
65257
65134
|
return turn.items.filter((item) => item.type === "agentMessage" && (item.phase === void 0 || item.phase === null || item.phase === "final_answer" || item.phase === "finalAnswer")).map((item) => item.text).filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
65258
65135
|
}
|
|
65136
|
+
function voiceIdsFromTurn(turn) {
|
|
65137
|
+
const ids = /* @__PURE__ */ new Set();
|
|
65138
|
+
const visit = (value) => {
|
|
65139
|
+
if (typeof value === "string") try {
|
|
65140
|
+
visit(JSON.parse(value));
|
|
65141
|
+
} catch {}
|
|
65142
|
+
else if (Array.isArray(value)) value.forEach(visit);
|
|
65143
|
+
else if (value && typeof value === "object") {
|
|
65144
|
+
const entry = value;
|
|
65145
|
+
if (entry.kind === "voice" && typeof entry.audioId === "string" && /^[a-f0-9]{64}$/u.test(entry.audioId)) ids.add(entry.audioId);
|
|
65146
|
+
Object.values(entry).forEach(visit);
|
|
65147
|
+
}
|
|
65148
|
+
};
|
|
65149
|
+
for (const item of turn?.items ?? []) if (item.type === "mcpToolCall" && item.status === "completed" && item.server === "companion" && item.tool === "send_voice") visit(item.result);
|
|
65150
|
+
return [...ids];
|
|
65151
|
+
}
|
|
65259
65152
|
function errorFromTurn(turn) {
|
|
65260
65153
|
if (!turn?.error) return null;
|
|
65261
65154
|
const error = record(turn.error);
|
|
@@ -65382,7 +65275,8 @@ function versionFromUserAgent(value) {
|
|
|
65382
65275
|
* ordinary resume safe without a second model journal.
|
|
65383
65276
|
*/
|
|
65384
65277
|
async function createPartner(config, credentials, dependencies = {}) {
|
|
65385
|
-
if (config.speech && !credentials.speech) throw new Error("
|
|
65278
|
+
if (config.speech?.tts?.provider === "alibaba" && !credentials.speech) throw new Error("Alibaba Voice requires a CLI-managed speech credential");
|
|
65279
|
+
if (config.speech?.tts?.provider === "bytedance" && !credentials.tts) throw new Error("ByteDance Voice requires a CLI-managed tts credential");
|
|
65386
65280
|
const persona = await readFile(config.persona, "utf8");
|
|
65387
65281
|
if (!persona.trim()) throw new Error("Persona must not be empty");
|
|
65388
65282
|
const paths = partnerPaths(config.workspace);
|
|
@@ -65752,6 +65646,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
65752
65646
|
const status = turnStatus(turn);
|
|
65753
65647
|
if (status === "completed") completedOperationId = sourceIds.at(-1) ?? completedOperationId;
|
|
65754
65648
|
const generatedIds = [];
|
|
65649
|
+
const voiceIds = voiceIdsFromTurn(turn);
|
|
65755
65650
|
let resultError = errorFromTurn(turn);
|
|
65756
65651
|
let resultStatus = status;
|
|
65757
65652
|
for (const item of turn.items ?? []) {
|
|
@@ -65769,7 +65664,8 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
65769
65664
|
answers: answersFromTurn(turn),
|
|
65770
65665
|
error: resultError,
|
|
65771
65666
|
status: resultStatus,
|
|
65772
|
-
generatedIds
|
|
65667
|
+
generatedIds,
|
|
65668
|
+
voiceIds
|
|
65773
65669
|
};
|
|
65774
65670
|
const fingerprint = JSON.stringify(resultBody);
|
|
65775
65671
|
const previous = presentationFingerprints.get(turn.id);
|
|
@@ -66097,7 +65993,9 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66097
65993
|
if (turnId && [
|
|
66098
65994
|
"userMessage",
|
|
66099
65995
|
"agentMessage",
|
|
66100
|
-
"imageGeneration"
|
|
65996
|
+
"imageGeneration",
|
|
65997
|
+
"mcpToolCall",
|
|
65998
|
+
"mcpToolResult"
|
|
66101
65999
|
].includes(typeof item.type === "string" ? item.type : "")) {
|
|
66102
66000
|
const turn = await reconcileTurn(turnId, void 0, typeof item.id !== "string" || typeof item.type !== "string");
|
|
66103
66001
|
if (turn && userItems(turn).length) await projectTurn(turn);
|
|
@@ -66183,7 +66081,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66183
66081
|
...config.codex.home ? { CODEX_HOME: config.codex.home } : {},
|
|
66184
66082
|
...injected.env ?? {}
|
|
66185
66083
|
};
|
|
66186
|
-
const hook = await ensureHookDeclaration(paths.workspaceRoot, contextFile);
|
|
66084
|
+
const hook = await ensureHookDeclaration(paths.workspaceRoot, contextFile, config.configPath);
|
|
66187
66085
|
let lastReportedSdkError;
|
|
66188
66086
|
const reportAppServerError = (error) => {
|
|
66189
66087
|
if (closing) return;
|
|
@@ -66331,18 +66229,6 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66331
66229
|
throw error;
|
|
66332
66230
|
}
|
|
66333
66231
|
},
|
|
66334
|
-
async synthesize(text, signal) {
|
|
66335
|
-
const tts = config.speech?.tts;
|
|
66336
|
-
const credential = tts?.provider === "alibaba" ? credentials.speech : credentials.tts;
|
|
66337
|
-
if (!tts || !credential) throw new Error("Speech synthesis is unavailable");
|
|
66338
|
-
return synthesizeSpeech({
|
|
66339
|
-
...tts,
|
|
66340
|
-
credential,
|
|
66341
|
-
text,
|
|
66342
|
-
audioDir: paths.audio,
|
|
66343
|
-
signal
|
|
66344
|
-
});
|
|
66345
|
-
},
|
|
66346
66232
|
async audio(id) {
|
|
66347
66233
|
try {
|
|
66348
66234
|
return await readFile(join(paths.audio, `${id}.mp3`));
|
|
@@ -66408,6 +66294,10 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66408
66294
|
id,
|
|
66409
66295
|
name,
|
|
66410
66296
|
url: `/api/images/${id}`
|
|
66297
|
+
})),
|
|
66298
|
+
voices: result.voiceIds.map((id) => ({
|
|
66299
|
+
id,
|
|
66300
|
+
url: `/api/audio/${id}.mp3`
|
|
66411
66301
|
}))
|
|
66412
66302
|
}));
|
|
66413
66303
|
const unresolved = await unresolvedMessages();
|
|
@@ -67241,7 +67131,7 @@ function json(response, value, status = 200) {
|
|
|
67241
67131
|
});
|
|
67242
67132
|
response.end(JSON.stringify(value));
|
|
67243
67133
|
}
|
|
67244
|
-
function createWebServer(partner, assets) {
|
|
67134
|
+
function createWebServer(partner, assets, options = {}) {
|
|
67245
67135
|
const serve = build_default(assets, {
|
|
67246
67136
|
single: true,
|
|
67247
67137
|
setHeaders(response, pathname) {
|
|
@@ -67323,12 +67213,6 @@ function createWebServer(partner, assets) {
|
|
|
67323
67213
|
response.end(image.data);
|
|
67324
67214
|
return;
|
|
67325
67215
|
}
|
|
67326
|
-
if (path === "/api/voice/synthesize" && request.method === "POST") {
|
|
67327
|
-
const parsed = object({ text: string().trim().min(1).max(240) }).strict().parse(await body(request));
|
|
67328
|
-
const abort = new AbortController();
|
|
67329
|
-
response.once("close", () => abort.abort());
|
|
67330
|
-
return json(response, { url: `/api/audio/${await partner.synthesize(parsed.text, abort.signal)}.mp3` });
|
|
67331
|
-
}
|
|
67332
67216
|
if (path.startsWith("/api/audio/") && request.method === "GET") {
|
|
67333
67217
|
const id = string().regex(/^[a-f0-9]{64}\.mp3$/u).parse(path.slice(11));
|
|
67334
67218
|
const audio = await partner.audio(id.slice(0, -4));
|
|
@@ -67386,7 +67270,7 @@ function createWebServer(partner, assets) {
|
|
|
67386
67270
|
if (!response.write("data: changed\n\n")) response.end();
|
|
67387
67271
|
};
|
|
67388
67272
|
const off = partner.subscribe(invalidate);
|
|
67389
|
-
const heartbeat = setInterval(() => response.write(":
|
|
67273
|
+
const heartbeat = setInterval(() => response.write("event: heartbeat\ndata: live\n\n"), options.heartbeatMs ?? 15e3);
|
|
67390
67274
|
invalidate();
|
|
67391
67275
|
response.once("close", () => {
|
|
67392
67276
|
off();
|