visionclaw 0.1.214-beta.0 → 0.1.214-beta.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/agent/external-context/finapp-capability.d.ts +2 -19
- package/dist/agent/external-context/finapp-capability.d.ts.map +1 -1
- package/dist/agent/external-context/finapp-capability.js +2 -23
- package/dist/agent/external-context/finapp-capability.js.map +1 -1
- package/dist/agent/external-context/interrupt.d.ts +13 -0
- package/dist/agent/external-context/interrupt.d.ts.map +1 -0
- package/dist/agent/external-context/interrupt.js +16 -0
- package/dist/agent/external-context/interrupt.js.map +1 -0
- package/dist/agent/external-context/providers/finapp.d.ts +15 -1
- package/dist/agent/external-context/providers/finapp.d.ts.map +1 -1
- package/dist/agent/external-context/providers/finapp.js +127 -50
- package/dist/agent/external-context/providers/finapp.js.map +1 -1
- package/dist/agent/external-context/registry.d.ts +15 -2
- package/dist/agent/external-context/registry.d.ts.map +1 -1
- package/dist/agent/external-context/registry.js +88 -8
- package/dist/agent/external-context/registry.js.map +1 -1
- package/dist/agent/external-context/runtime.d.ts +3 -1
- package/dist/agent/external-context/runtime.d.ts.map +1 -1
- package/dist/agent/external-context/runtime.js +7 -1
- package/dist/agent/external-context/runtime.js.map +1 -1
- package/dist/agent/external-context/types.d.ts +22 -0
- package/dist/agent/external-context/types.d.ts.map +1 -1
- package/dist/agent/interrupt-handler.d.ts +7 -3
- package/dist/agent/interrupt-handler.d.ts.map +1 -1
- package/dist/agent/interrupt-handler.js +39 -26
- package/dist/agent/interrupt-handler.js.map +1 -1
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +10 -4
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/system-prompt.d.ts +5 -3
- package/dist/agent/system-prompt.d.ts.map +1 -1
- package/dist/agent/system-prompt.js +4 -14
- package/dist/agent/system-prompt.js.map +1 -1
- package/dist/agent/wake-cycle-runner.d.ts +3 -0
- package/dist/agent/wake-cycle-runner.d.ts.map +1 -1
- package/dist/agent/wake-cycle-runner.js +11 -6
- package/dist/agent/wake-cycle-runner.js.map +1 -1
- package/dist/channels/credential-backed.d.ts +10 -0
- package/dist/channels/credential-backed.d.ts.map +1 -0
- package/dist/channels/credential-backed.js +12 -0
- package/dist/channels/credential-backed.js.map +1 -0
- package/dist/channels/manager.d.ts +4 -1
- package/dist/channels/manager.d.ts.map +1 -1
- package/dist/channels/manager.js +47 -33
- package/dist/channels/manager.js.map +1 -1
- package/dist/channels/telegram-status.d.ts +3 -0
- package/dist/channels/telegram-status.d.ts.map +1 -1
- package/dist/channels/telegram-status.js +53 -8
- package/dist/channels/telegram-status.js.map +1 -1
- package/dist/data-processing/batch-process.d.ts.map +1 -1
- package/dist/data-processing/batch-process.js +2 -1
- package/dist/data-processing/batch-process.js.map +1 -1
- package/dist/event-trigger/providers/finapp-monitor.d.ts +3 -0
- package/dist/event-trigger/providers/finapp-monitor.d.ts.map +1 -0
- package/dist/event-trigger/providers/finapp-monitor.js +25 -0
- package/dist/event-trigger/providers/finapp-monitor.js.map +1 -0
- package/dist/event-trigger/sidecar.d.ts +10 -6
- package/dist/event-trigger/sidecar.d.ts.map +1 -1
- package/dist/event-trigger/sidecar.js +18 -50
- package/dist/event-trigger/sidecar.js.map +1 -1
- package/dist/event-trigger/wake-routing.d.ts +21 -0
- package/dist/event-trigger/wake-routing.d.ts.map +1 -0
- package/dist/event-trigger/wake-routing.js +38 -0
- package/dist/event-trigger/wake-routing.js.map +1 -0
- package/dist-agent/bundle.cjs +2541 -2247
- package/package.json +4 -3
|
@@ -1,27 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* in-flight turn does not keep a stale client fence set.
|
|
2
|
+
* Fin-App-specific interpretation of client capability metadata.
|
|
3
|
+
* The external-context registry owns collection and interrupt refresh.
|
|
5
4
|
*/
|
|
6
|
-
import type { VisionClawConfig } from "../../config/types.js";
|
|
7
5
|
import type { CommandMessage } from "../../channels/interface.js";
|
|
8
|
-
import type { SessionMode } from "../mailbox.js";
|
|
9
6
|
/** True when any message carries Fin-App fence capability meta. */
|
|
10
7
|
export declare function batchHasFinAppFenceCapability(messages: readonly CommandMessage[]): boolean;
|
|
11
|
-
/**
|
|
12
|
-
* Recollect Fin-App external context from `messages` and publish it as the
|
|
13
|
-
* current wake's external context. No-op when the batch has no Fin-App fence
|
|
14
|
-
* capability meta (keeps the prior wake catalog intact for non-finapp interrupts).
|
|
15
|
-
*/
|
|
16
|
-
export declare function refreshFinAppExternalContextFromMessages(input: {
|
|
17
|
-
config: VisionClawConfig;
|
|
18
|
-
messages: readonly CommandMessage[];
|
|
19
|
-
sessionMode: SessionMode;
|
|
20
|
-
trigger?: "message" | "heartbeat";
|
|
21
|
-
}): Promise<{
|
|
22
|
-
refreshed: boolean;
|
|
23
|
-
digest: string | null;
|
|
24
|
-
}>;
|
|
25
8
|
/**
|
|
26
9
|
* Text blocks that force an in-flight model turn to see the new client fence
|
|
27
10
|
* catalog even when the session system prompt was baked at wake start.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"finapp-capability.d.ts","sourceRoot":"","sources":["../../../src/agent/external-context/finapp-capability.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"finapp-capability.d.ts","sourceRoot":"","sources":["../../../src/agent/external-context/finapp-capability.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,mEAAmE;AACnE,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,OAAO,CAQ1F;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,MAAM,GAAG,IAAI,CA4BhG"}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* in-flight turn does not keep a stale client fence set.
|
|
2
|
+
* Fin-App-specific interpretation of client capability metadata.
|
|
3
|
+
* The external-context registry owns collection and interrupt refresh.
|
|
5
4
|
*/
|
|
6
|
-
import { createDefaultExternalContextRegistry } from "./registry.js";
|
|
7
|
-
import { setCurrentExternalContext } from "./runtime.js";
|
|
8
5
|
/** True when any message carries Fin-App fence capability meta. */
|
|
9
6
|
export function batchHasFinAppFenceCapability(messages) {
|
|
10
7
|
return messages.some((msg) => {
|
|
@@ -16,24 +13,6 @@ export function batchHasFinAppFenceCapability(messages) {
|
|
|
16
13
|
|| (typeof restrict === "string" && restrict.trim().length > 0);
|
|
17
14
|
});
|
|
18
15
|
}
|
|
19
|
-
/**
|
|
20
|
-
* Recollect Fin-App external context from `messages` and publish it as the
|
|
21
|
-
* current wake's external context. No-op when the batch has no Fin-App fence
|
|
22
|
-
* capability meta (keeps the prior wake catalog intact for non-finapp interrupts).
|
|
23
|
-
*/
|
|
24
|
-
export async function refreshFinAppExternalContextFromMessages(input) {
|
|
25
|
-
if (!batchHasFinAppFenceCapability(input.messages)) {
|
|
26
|
-
return { refreshed: false, digest: null };
|
|
27
|
-
}
|
|
28
|
-
const registry = createDefaultExternalContextRegistry(input.config);
|
|
29
|
-
const result = await registry.collect({
|
|
30
|
-
trigger: input.trigger ?? "message",
|
|
31
|
-
sessionMode: input.sessionMode,
|
|
32
|
-
messages: [...input.messages],
|
|
33
|
-
});
|
|
34
|
-
setCurrentExternalContext(result.section, result.digest);
|
|
35
|
-
return { refreshed: true, digest: result.digest };
|
|
36
|
-
}
|
|
37
16
|
/**
|
|
38
17
|
* Text blocks that force an in-flight model turn to see the new client fence
|
|
39
18
|
* catalog even when the session system prompt was baked at wake start.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"finapp-capability.js","sourceRoot":"","sources":["../../../src/agent/external-context/finapp-capability.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"finapp-capability.js","sourceRoot":"","sources":["../../../src/agent/external-context/finapp-capability.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,mEAAmE;AACnE,MAAM,UAAU,6BAA6B,CAAC,QAAmC;IAC/E,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QAC3B,IAAI,GAAG,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,kBAAkB,CAAC;QAC7C,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,EAAE,qBAAqB,CAAC;QACjD,OAAO,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;eAC5D,CAAC,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,6BAA6B,CAAC,QAAmC;IAC/E,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACjD,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,GAAG,CAAC,OAAO,KAAK,QAAQ;YAAE,SAAS;QACvC,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,IAAI,EAAE,kBAAkB,KAAK,QAAQ;YAC9D,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE;YACpC,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,QAAQ,GAAG,OAAO,GAAG,CAAC,IAAI,EAAE,qBAAqB,KAAK,QAAQ;YAClE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,qBAAqB,CAAC,IAAI,EAAE;YACvC,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ;YAAE,SAAS;QACpC,MAAM,KAAK,GAAG;YACZ,wHAAwH;SACzH,CAAC;QACF,IAAI,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,0EAA0E;YAC1E,sEAAsE;YACtE,qEAAqE;YACrE,KAAK,CAAC,IAAI,CACR,kHAAkH,CACnH,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CommandMessage } from "../../channels/interface.js";
|
|
2
|
+
import type { SessionMode } from "../mailbox.js";
|
|
3
|
+
import type { ExternalContextRegistry } from "./registry.js";
|
|
4
|
+
/** Keep the existing wake context when no provider recognizes an interrupt update. */
|
|
5
|
+
export declare function refreshExternalContextFromMessages(input: {
|
|
6
|
+
messages: readonly CommandMessage[];
|
|
7
|
+
sessionMode: SessionMode;
|
|
8
|
+
trigger?: "message" | "heartbeat";
|
|
9
|
+
}, registry: ExternalContextRegistry): Promise<{
|
|
10
|
+
refreshed: boolean;
|
|
11
|
+
digest: string | null;
|
|
12
|
+
}>;
|
|
13
|
+
//# sourceMappingURL=interrupt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interrupt.d.ts","sourceRoot":"","sources":["../../../src/agent/external-context/interrupt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAG7D,sFAAsF;AACtF,wBAAsB,kCAAkC,CAAC,KAAK,EAAE;IAC9D,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IACpC,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;CACnC,EAAE,QAAQ,EAAE,uBAAuB,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAW5F"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getCurrentExternalContextProviderBlocks, setCurrentExternalContext } from "./runtime.js";
|
|
2
|
+
/** Keep the existing wake context when no provider recognizes an interrupt update. */
|
|
3
|
+
export async function refreshExternalContextFromMessages(input, registry) {
|
|
4
|
+
if (!registry.ownsInterrupt(input.messages))
|
|
5
|
+
return { refreshed: false, digest: null };
|
|
6
|
+
const result = await registry.collect({
|
|
7
|
+
trigger: input.trigger ?? "message",
|
|
8
|
+
sessionMode: input.sessionMode,
|
|
9
|
+
messages: [...input.messages],
|
|
10
|
+
interrupt: true,
|
|
11
|
+
previousProviderBlocks: getCurrentExternalContextProviderBlocks(),
|
|
12
|
+
});
|
|
13
|
+
setCurrentExternalContext(result.section, result.digest, result.providerBlocks);
|
|
14
|
+
return { refreshed: true, digest: result.digest };
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=interrupt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interrupt.js","sourceRoot":"","sources":["../../../src/agent/external-context/interrupt.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,uCAAuC,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAElG,sFAAsF;AACtF,MAAM,CAAC,KAAK,UAAU,kCAAkC,CAAC,KAIxD,EAAE,QAAiC;IAClC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACvF,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC;QACpC,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,SAAS;QACnC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,QAAQ,EAAE,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC7B,SAAS,EAAE,IAAI;QACf,sBAAsB,EAAE,uCAAuC,EAAE;KAClE,CAAC,CAAC;IACH,yBAAyB,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;IAChF,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;AACpD,CAAC"}
|
|
@@ -1,10 +1,24 @@
|
|
|
1
|
+
import { type CommandMessage } from "../../../channels/interface.js";
|
|
1
2
|
import type { VisionClawConfig } from "../../../config/types.js";
|
|
2
|
-
import type { ExternalContextBlock, ExternalContextProvider, ExternalContextProviderInput } from "../types.js";
|
|
3
|
+
import type { ExternalContextBlock, ExternalContextProvider, ExternalContextProviderInput, ExternalConversationContext } from "../types.js";
|
|
3
4
|
export declare class FinAppExternalContextProvider implements ExternalContextProvider {
|
|
4
5
|
private readonly config;
|
|
5
6
|
readonly source = "fin-app";
|
|
7
|
+
private credentialScope;
|
|
6
8
|
private readonly cache;
|
|
7
9
|
constructor(config: VisionClawConfig);
|
|
10
|
+
selectMessage(input: ExternalContextProviderInput): CommandMessage | undefined;
|
|
11
|
+
systemPrompt(conversation: ExternalConversationContext): string | null;
|
|
12
|
+
ownsInterrupt(messages: readonly CommandMessage[]): boolean;
|
|
13
|
+
canReuseContext(input: ExternalContextProviderInput, blocks: readonly ExternalContextBlock[]): boolean;
|
|
14
|
+
build(input: ExternalContextProviderInput): Promise<ExternalContextBlock[]>;
|
|
15
|
+
}
|
|
16
|
+
/** Local client capabilities have their own snapshot and cannot be lost to a remote fetch timeout. */
|
|
17
|
+
export declare class FinAppClientContextProvider implements ExternalContextProvider {
|
|
18
|
+
readonly source = "fin-app-client";
|
|
19
|
+
selectMessage(input: ExternalContextProviderInput): CommandMessage | undefined;
|
|
20
|
+
ownsInterrupt(messages: readonly CommandMessage[]): boolean;
|
|
21
|
+
interruptText(messages: readonly CommandMessage[]): string | null;
|
|
8
22
|
build(input: ExternalContextProviderInput): Promise<ExternalContextBlock[]>;
|
|
9
23
|
}
|
|
10
24
|
//# sourceMappingURL=finapp.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"finapp.d.ts","sourceRoot":"","sources":["../../../../src/agent/external-context/providers/finapp.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"finapp.d.ts","sourceRoot":"","sources":["../../../../src/agent/external-context/providers/finapp.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAGtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAgB5I,qBAAa,6BAA8B,YAAW,uBAAuB;IAK/D,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,QAAQ,CAAC,MAAM,aAAa;IAC5B,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyE;gBAElE,MAAM,EAAE,gBAAgB;IAErD,aAAa,CAAC,KAAK,EAAE,4BAA4B,GAAG,cAAc,GAAG,SAAS;IAI9E,YAAY,CAAC,YAAY,EAAE,2BAA2B,GAAG,MAAM,GAAG,IAAI;IAMtE,aAAa,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,OAAO;IAI3D,eAAe,CAAC,KAAK,EAAE,4BAA4B,EAAE,MAAM,EAAE,SAAS,oBAAoB,EAAE,GAAG,OAAO;IAShG,KAAK,CAAC,KAAK,EAAE,4BAA4B,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;CAiElF;AAeD,sGAAsG;AACtG,qBAAa,2BAA4B,YAAW,uBAAuB;IACzE,QAAQ,CAAC,MAAM,oBAAoB;IAEnC,aAAa,CAAC,KAAK,EAAE,4BAA4B,GAAG,cAAc,GAAG,SAAS;IAI9E,aAAa,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,OAAO;IAI3D,aAAa,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,MAAM,GAAG,IAAI;IAIjE,KAAK,CAAC,KAAK,EAAE,4BAA4B,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;CA4C5E"}
|
|
@@ -1,64 +1,55 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
+
import { resolveThreadId } from "../../../channels/interface.js";
|
|
3
|
+
import { isFinAppThreadId, isFinAppThreadMessage, loadFinAppCoreContract } from "../../fin-app/core-contract.js";
|
|
4
|
+
import { batchHasFinAppFenceCapability, finAppCapabilityInterruptText } from "../finapp-capability.js";
|
|
2
5
|
import { resolveFinAppCredentials } from "../../../finapp-credentials.js";
|
|
3
6
|
const CONTEXT_CACHE_TTL_MS = 45_000;
|
|
4
7
|
export class FinAppExternalContextProvider {
|
|
5
8
|
config;
|
|
6
9
|
source = "fin-app";
|
|
10
|
+
credentialScope = null;
|
|
7
11
|
cache = new Map();
|
|
8
12
|
constructor(config) {
|
|
9
13
|
this.config = config;
|
|
10
14
|
}
|
|
15
|
+
selectMessage(input) {
|
|
16
|
+
return selectFinAppMessage(input);
|
|
17
|
+
}
|
|
18
|
+
systemPrompt(conversation) {
|
|
19
|
+
if (!isFinAppThreadId(conversation.threadId) && !conversation.messages?.some(isFinAppThreadMessage))
|
|
20
|
+
return null;
|
|
21
|
+
return loadFinAppCoreContract()
|
|
22
|
+
?? "## Fin-App Core Contract\n\nThe Fin-App core contract could not be loaded. Do not perform Fin-App writes or provide renderer-sensitive output until the contract is available.";
|
|
23
|
+
}
|
|
24
|
+
ownsInterrupt(messages) {
|
|
25
|
+
return batchHasFinAppFenceCapability(messages);
|
|
26
|
+
}
|
|
27
|
+
canReuseContext(input, blocks) {
|
|
28
|
+
const scope = credentialScope(resolveFinAppCredentials(this.config));
|
|
29
|
+
const message = selectFinAppMessage(input);
|
|
30
|
+
const threadId = message ? resolveThreadId(message) : undefined;
|
|
31
|
+
const key = threadId ? contextCacheKey(threadId, message?.meta ?? {}) : undefined;
|
|
32
|
+
return scope !== null && blocks.every((block) => block.metadata?.credentialScope === scope
|
|
33
|
+
&& (!key || block.metadata.cacheKey === key));
|
|
34
|
+
}
|
|
11
35
|
async build(input) {
|
|
12
36
|
if (input.channel !== "finapp")
|
|
13
37
|
return [];
|
|
14
|
-
const blocks = [];
|
|
15
|
-
const fenceCatalog = typeof input.channelMeta.fenceCatalogPrompt === "string"
|
|
16
|
-
? input.channelMeta.fenceCatalogPrompt.trim()
|
|
17
|
-
: "";
|
|
18
|
-
if (fenceCatalog) {
|
|
19
|
-
blocks.push({
|
|
20
|
-
source: "fin-app-fence-catalog",
|
|
21
|
-
scope: "thread",
|
|
22
|
-
threadId: input.threadId,
|
|
23
|
-
title: "Fin-App fence catalog",
|
|
24
|
-
generatedAt: new Date().toISOString(),
|
|
25
|
-
digest: crypto.createHash("sha256").update(fenceCatalog).digest("hex").slice(0, 16),
|
|
26
|
-
// Above thread context and above the forbid appendix so schemas win.
|
|
27
|
-
priority: 115,
|
|
28
|
-
content: fenceCatalog,
|
|
29
|
-
metadata: {
|
|
30
|
-
clientFences: input.channelMeta.clientFences,
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
const fencePrompt = typeof input.channelMeta.fenceCapabilityPrompt === "string"
|
|
35
|
-
? input.channelMeta.fenceCapabilityPrompt.trim()
|
|
36
|
-
: "";
|
|
37
|
-
if (fencePrompt) {
|
|
38
|
-
blocks.push({
|
|
39
|
-
source: "fin-app-fences",
|
|
40
|
-
scope: "thread",
|
|
41
|
-
threadId: input.threadId,
|
|
42
|
-
title: "Fin-App client fences",
|
|
43
|
-
generatedAt: new Date().toISOString(),
|
|
44
|
-
digest: crypto.createHash("sha256").update(fencePrompt).digest("hex").slice(0, 16),
|
|
45
|
-
priority: 110,
|
|
46
|
-
content: fencePrompt,
|
|
47
|
-
metadata: {
|
|
48
|
-
clientFences: input.channelMeta.clientFences,
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
38
|
const credentials = resolveFinAppCredentials(this.config);
|
|
39
|
+
// A shared provider must never reuse data after credentials/service scope changes.
|
|
40
|
+
const scope = credentialScope(credentials);
|
|
41
|
+
if (scope !== this.credentialScope) {
|
|
42
|
+
this.cache.clear();
|
|
43
|
+
this.credentialScope = scope;
|
|
44
|
+
}
|
|
53
45
|
if (!credentials)
|
|
54
|
-
return
|
|
46
|
+
return [];
|
|
55
47
|
const userId = typeof input.channelMeta.userId === "number" ? input.channelMeta.userId : undefined;
|
|
56
|
-
const locale = input.channelMeta.locale === "zh" ? "zh" : input.channelMeta.locale === "en" ? "en" : "unknown";
|
|
57
48
|
const messageKind = input.channelMeta.kind === "system" ? "system" : "user";
|
|
58
|
-
const cacheKey =
|
|
49
|
+
const cacheKey = contextCacheKey(input.threadId, input.channelMeta);
|
|
59
50
|
const cached = this.cache.get(cacheKey);
|
|
60
51
|
if (cached && Date.now() - cached.fetchedAt < CONTEXT_CACHE_TTL_MS) {
|
|
61
|
-
return [
|
|
52
|
+
return [cached.block];
|
|
62
53
|
}
|
|
63
54
|
try {
|
|
64
55
|
const response = await fetch(`${credentials.baseUrl}/api/internal/thread-context`, {
|
|
@@ -68,14 +59,18 @@ export class FinAppExternalContextProvider {
|
|
|
68
59
|
"Content-Type": "application/json",
|
|
69
60
|
},
|
|
70
61
|
body: JSON.stringify({ threadKey: input.threadId, ...(userId !== undefined ? { userId } : {}) }),
|
|
71
|
-
signal: AbortSignal.timeout(900),
|
|
62
|
+
signal: input.signal ? AbortSignal.any([input.signal, AbortSignal.timeout(900)]) : AbortSignal.timeout(900),
|
|
72
63
|
});
|
|
64
|
+
if (credentialScope(resolveFinAppCredentials(this.config)) !== scope)
|
|
65
|
+
return [];
|
|
66
|
+
input.signal?.throwIfAborted();
|
|
73
67
|
if (!response.ok) {
|
|
74
|
-
|
|
75
|
-
return [...blocks, withDegradedReason(cached.block, `fin-app context endpoint HTTP ${response.status}`)];
|
|
76
|
-
return blocks;
|
|
68
|
+
throw new Error(`fin-app context endpoint HTTP ${response.status}`);
|
|
77
69
|
}
|
|
78
70
|
const context = await response.json();
|
|
71
|
+
if (credentialScope(resolveFinAppCredentials(this.config)) !== scope)
|
|
72
|
+
return [];
|
|
73
|
+
input.signal?.throwIfAborted();
|
|
79
74
|
const block = {
|
|
80
75
|
source: "fin-app",
|
|
81
76
|
scope: "thread",
|
|
@@ -87,19 +82,101 @@ export class FinAppExternalContextProvider {
|
|
|
87
82
|
priority: 100,
|
|
88
83
|
content: renderFinAppContext(context, messageKind),
|
|
89
84
|
metadata: {
|
|
85
|
+
credentialScope: scope,
|
|
86
|
+
cacheKey,
|
|
90
87
|
threadKey: context.threadKey,
|
|
91
88
|
degradedReason: context.degradedReason,
|
|
92
89
|
},
|
|
93
90
|
};
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
// A request from the previous credential scope may finish after rotation.
|
|
92
|
+
if (this.credentialScope === scope)
|
|
93
|
+
this.cache.set(cacheKey, { fetchedAt: Date.now(), block });
|
|
94
|
+
return [block];
|
|
96
95
|
}
|
|
97
96
|
catch (err) {
|
|
97
|
+
if (credentialScope(resolveFinAppCredentials(this.config)) !== scope)
|
|
98
|
+
return [];
|
|
98
99
|
if (cached)
|
|
99
|
-
return [
|
|
100
|
-
|
|
100
|
+
return [withDegradedReason(cached.block, err instanceof Error ? err.message : String(err))];
|
|
101
|
+
// Transient failure must reach the registry so it can reuse a valid snapshot.
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function credentialScope(credentials) {
|
|
107
|
+
return credentials
|
|
108
|
+
? crypto.createHash("sha256").update(JSON.stringify([credentials.baseUrl, credentials.apiKey])).digest("hex")
|
|
109
|
+
: null;
|
|
110
|
+
}
|
|
111
|
+
function contextCacheKey(threadId, meta) {
|
|
112
|
+
const userId = typeof meta.userId === "number" ? meta.userId : "unknown";
|
|
113
|
+
const locale = meta.locale === "zh" ? "zh" : meta.locale === "en" ? "en" : "unknown";
|
|
114
|
+
const kind = meta.kind === "system" ? "system" : "user";
|
|
115
|
+
return JSON.stringify([userId, threadId, locale, kind]);
|
|
116
|
+
}
|
|
117
|
+
/** Local client capabilities have their own snapshot and cannot be lost to a remote fetch timeout. */
|
|
118
|
+
export class FinAppClientContextProvider {
|
|
119
|
+
source = "fin-app-client";
|
|
120
|
+
selectMessage(input) {
|
|
121
|
+
return selectFinAppMessage(input);
|
|
122
|
+
}
|
|
123
|
+
ownsInterrupt(messages) {
|
|
124
|
+
return batchHasFinAppFenceCapability(messages);
|
|
125
|
+
}
|
|
126
|
+
interruptText(messages) {
|
|
127
|
+
return finAppCapabilityInterruptText(messages);
|
|
128
|
+
}
|
|
129
|
+
build(input) {
|
|
130
|
+
if (input.channel !== "finapp")
|
|
131
|
+
return Promise.resolve([]);
|
|
132
|
+
const blocks = [];
|
|
133
|
+
const fenceCatalog = typeof input.channelMeta.fenceCatalogPrompt === "string"
|
|
134
|
+
? input.channelMeta.fenceCatalogPrompt.trim()
|
|
135
|
+
: "";
|
|
136
|
+
if (fenceCatalog) {
|
|
137
|
+
blocks.push({
|
|
138
|
+
source: "fin-app-fence-catalog",
|
|
139
|
+
scope: "thread",
|
|
140
|
+
threadId: input.threadId,
|
|
141
|
+
title: "Fin-App fence catalog",
|
|
142
|
+
generatedAt: new Date().toISOString(),
|
|
143
|
+
digest: crypto.createHash("sha256").update(fenceCatalog).digest("hex").slice(0, 16),
|
|
144
|
+
// Above thread context and above the forbid appendix so schemas win.
|
|
145
|
+
priority: 115,
|
|
146
|
+
content: fenceCatalog,
|
|
147
|
+
metadata: {
|
|
148
|
+
clientFences: input.channelMeta.clientFences,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
101
151
|
}
|
|
152
|
+
const fencePrompt = typeof input.channelMeta.fenceCapabilityPrompt === "string"
|
|
153
|
+
? input.channelMeta.fenceCapabilityPrompt.trim()
|
|
154
|
+
: "";
|
|
155
|
+
if (fencePrompt) {
|
|
156
|
+
blocks.push({
|
|
157
|
+
source: "fin-app-fences",
|
|
158
|
+
scope: "thread",
|
|
159
|
+
threadId: input.threadId,
|
|
160
|
+
title: "Fin-App client fences",
|
|
161
|
+
generatedAt: new Date().toISOString(),
|
|
162
|
+
digest: crypto.createHash("sha256").update(fencePrompt).digest("hex").slice(0, 16),
|
|
163
|
+
priority: 110,
|
|
164
|
+
content: fencePrompt,
|
|
165
|
+
metadata: {
|
|
166
|
+
clientFences: input.channelMeta.clientFences,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return Promise.resolve(blocks);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function selectFinAppMessage(input) {
|
|
174
|
+
if (input.interrupt) {
|
|
175
|
+
const latestUpdate = [...input.messages].reverse().find((message) => batchHasFinAppFenceCapability([message]));
|
|
176
|
+
if (latestUpdate)
|
|
177
|
+
return latestUpdate;
|
|
102
178
|
}
|
|
179
|
+
return input.messages.find((message) => message.channel === "finapp");
|
|
103
180
|
}
|
|
104
181
|
function renderFinAppContext(context, messageKind) {
|
|
105
182
|
const lines = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"finapp.js","sourceRoot":"","sources":["../../../../src/agent/external-context/providers/finapp.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"finapp.js","sourceRoot":"","sources":["../../../../src/agent/external-context/providers/finapp.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,eAAe,EAAuB,MAAM,gCAAgC,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACjH,OAAO,EAAE,6BAA6B,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAEvG,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAe1E,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAEpC,MAAM,OAAO,6BAA6B;IAKX;IAJpB,MAAM,GAAG,SAAS,CAAC;IACpB,eAAe,GAAkB,IAAI,CAAC;IAC7B,KAAK,GAAG,IAAI,GAAG,EAA8D,CAAC;IAE/F,YAA6B,MAAwB;QAAxB,WAAM,GAAN,MAAM,CAAkB;IAAG,CAAC;IAEzD,aAAa,CAAC,KAAmC;QAC/C,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAED,YAAY,CAAC,YAAyC;QACpD,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,qBAAqB,CAAC;YAAE,OAAO,IAAI,CAAC;QACjH,OAAO,sBAAsB,EAAE;eAC1B,gLAAgL,CAAC;IACxL,CAAC;IAED,aAAa,CAAC,QAAmC;QAC/C,OAAO,6BAA6B,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED,eAAe,CAAC,KAAmC,EAAE,MAAuC;QAC1F,MAAM,KAAK,GAAG,eAAe,CAAC,wBAAwB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAChE,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAClF,OAAO,KAAK,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,eAAe,KAAK,KAAK;eACrF,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAmC;QAC7C,IAAI,KAAK,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QAE1C,MAAM,WAAW,GAAG,wBAAwB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1D,mFAAmF;QACnF,MAAM,KAAK,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;QAC3C,IAAI,KAAK,KAAK,IAAI,CAAC,eAAe,EAAE,CAAC;YACnC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACnB,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,WAAW;YAAE,OAAO,EAAE,CAAC;QAE5B,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,WAAW,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QACnG,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;QAC5E,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;QACpE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,oBAAoB,EAAE,CAAC;YACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,WAAW,CAAC,OAAO,8BAA8B,EAAE;gBACjF,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,WAAW,CAAC,MAAM,EAAE;oBAC7C,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;gBAChG,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC;aAC5G,CAAC,CAAC;YACH,IAAI,eAAe,CAAC,wBAAwB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK;gBAAE,OAAO,EAAE,CAAC;YAChF,KAAK,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;YAC/B,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YACtE,CAAC;YACD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAiC,CAAC;YACrE,IAAI,eAAe,CAAC,wBAAwB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK;gBAAE,OAAO,EAAE,CAAC;YAChF,KAAK,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAyB;gBAClC,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE,QAAQ;gBACf,QAAQ,EAAE,OAAO,CAAC,SAAS;gBAC3B,KAAK,EAAE,SAAS;gBAChB,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,QAAQ,EAAE,GAAG;gBACb,OAAO,EAAE,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC;gBAClD,QAAQ,EAAE;oBACR,eAAe,EAAE,KAAK;oBACtB,QAAQ;oBACR,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,cAAc,EAAE,OAAO,CAAC,cAAc;iBACvC;aACF,CAAC;YACF,0EAA0E;YAC1E,IAAI,IAAI,CAAC,eAAe,KAAK,KAAK;gBAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YAC/F,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,eAAe,CAAC,wBAAwB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK;gBAAE,OAAO,EAAE,CAAC;YAChF,IAAI,MAAM;gBAAE,OAAO,CAAC,kBAAkB,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACxG,8EAA8E;YAC9E,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CACF;AAED,SAAS,eAAe,CAAC,WAAwD;IAC/E,OAAO,WAAW;QAChB,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;QAC7G,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,SAAS,eAAe,CAAC,QAAgB,EAAE,IAA6B;IACtE,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACzE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACrF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;IACxD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,sGAAsG;AACtG,MAAM,OAAO,2BAA2B;IAC7B,MAAM,GAAG,gBAAgB,CAAC;IAEnC,aAAa,CAAC,KAAmC;QAC/C,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAED,aAAa,CAAC,QAAmC;QAC/C,OAAO,6BAA6B,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED,aAAa,CAAC,QAAmC;QAC/C,OAAO,6BAA6B,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,KAAmC;QACvC,IAAI,KAAK,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAE3D,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,MAAM,YAAY,GAAG,OAAO,KAAK,CAAC,WAAW,CAAC,kBAAkB,KAAK,QAAQ;YAC3E,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,kBAAkB,CAAC,IAAI,EAAE;YAC7C,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC;gBACV,MAAM,EAAE,uBAAuB;gBAC/B,KAAK,EAAE,QAAQ;gBACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,KAAK,EAAE,uBAAuB;gBAC9B,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACrC,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;gBACnF,qEAAqE;gBACrE,QAAQ,EAAE,GAAG;gBACb,OAAO,EAAE,YAAY;gBACrB,QAAQ,EAAE;oBACR,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,YAAY;iBAC7C;aACF,CAAC,CAAC;QACL,CAAC;QACD,MAAM,WAAW,GAAG,OAAO,KAAK,CAAC,WAAW,CAAC,qBAAqB,KAAK,QAAQ;YAC7E,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,qBAAqB,CAAC,IAAI,EAAE;YAChD,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,CAAC,IAAI,CAAC;gBACV,MAAM,EAAE,gBAAgB;gBACxB,KAAK,EAAE,QAAQ;gBACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,KAAK,EAAE,uBAAuB;gBAC9B,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACrC,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;gBAClF,QAAQ,EAAE,GAAG;gBACb,OAAO,EAAE,WAAW;gBACpB,QAAQ,EAAE;oBACR,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,YAAY;iBAC7C;aACF,CAAC,CAAC;QACL,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CACF;AAED,SAAS,mBAAmB,CAAC,KAAmC;IAC9D,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,MAAM,YAAY,GAAG,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,6BAA6B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC/G,IAAI,YAAY;YAAE,OAAO,YAAY,CAAC;IACxC,CAAC;IACD,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAoC,EAAE,WAA8B;IAC/F,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,2BAA2B,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAC3D,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QACjE,MAAM,UAAU,GAAG,WAAW,KAAK,QAAQ;YACzC,CAAC,CAAC,gIAAgI;YAClI,CAAC,CAAC,kHAAkH,CAAC;QACvH,KAAK,CAAC,IAAI,CAAC,6BAA6B,QAAQ,kEAAkE,UAAU,4EAA4E,CAAC,CAAC;IAC5M,CAAC;IACD,IAAI,OAAO,CAAC,cAAc;QAAE,KAAK,CAAC,IAAI,CAAC,aAAa,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC9E,KAAK,CAAC,IAAI,CAAC,uEAAuE,CAAC,CAAC;IACpF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACxC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IACtC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACvC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IAC3C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,eAAe,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC;AACjE,CAAC;AAED,SAAS,kBAAkB,CAAC,KAA2B,EAAE,MAAc;IACrE,OAAO;QACL,GAAG,KAAK;QACR,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,iEAAiE,MAAM,EAAE;QAClG,QAAQ,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE;KAC7E,CAAC;AACJ,CAAC"}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import type { VisionClawConfig } from "../../config/types.js";
|
|
2
2
|
import { type CommandMessage } from "../../channels/interface.js";
|
|
3
3
|
import type { SessionMode } from "../mailbox.js";
|
|
4
|
-
import type { ExternalContextBlock, ExternalContextProvider, ExternalContextRenderResult, ExternalContextTrigger } from "./types.js";
|
|
4
|
+
import type { ExternalContextBlock, ExternalContextCollectionResult, ExternalContextProvider, ExternalContextRenderResult, ExternalContextTrigger, ExternalConversationContext } from "./types.js";
|
|
5
5
|
export interface ExternalContextRegistryOptions {
|
|
6
6
|
maxChars?: number;
|
|
7
7
|
providerTimeoutMs?: number;
|
|
8
8
|
}
|
|
9
|
+
/** Text hooks can contain mandatory contracts; never silently omit a failed hook. */
|
|
10
|
+
export declare class ExternalContextHookError extends Error {
|
|
11
|
+
readonly source: string;
|
|
12
|
+
readonly hook: "systemPrompt" | "interruptText";
|
|
13
|
+
constructor(source: string, hook: "systemPrompt" | "interruptText", cause: unknown);
|
|
14
|
+
}
|
|
9
15
|
export declare class ExternalContextRegistry {
|
|
10
16
|
private readonly providers;
|
|
11
17
|
private readonly maxChars;
|
|
@@ -15,7 +21,14 @@ export declare class ExternalContextRegistry {
|
|
|
15
21
|
trigger: ExternalContextTrigger;
|
|
16
22
|
sessionMode: SessionMode;
|
|
17
23
|
messages: CommandMessage[];
|
|
18
|
-
|
|
24
|
+
interrupt?: boolean;
|
|
25
|
+
previousProviderBlocks?: ExternalContextCollectionResult["providerBlocks"];
|
|
26
|
+
}): Promise<ExternalContextCollectionResult>;
|
|
27
|
+
systemPrompt(conversation: ExternalConversationContext): string;
|
|
28
|
+
ownsInterrupt(messages: readonly CommandMessage[]): boolean;
|
|
29
|
+
private providerOwnsInterrupt;
|
|
30
|
+
interruptText(messages: readonly CommandMessage[]): string | null;
|
|
31
|
+
private collectText;
|
|
19
32
|
private buildWithTimeout;
|
|
20
33
|
}
|
|
21
34
|
export declare function createDefaultExternalContextRegistry(config: VisionClawConfig): ExternalContextRegistry;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/agent/external-context/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAEnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EACV,oBAAoB,EACpB,uBAAuB,EAEvB,2BAA2B,EAC3B,sBAAsB,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/agent/external-context/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAEnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EACV,oBAAoB,EACpB,+BAA+B,EAC/B,uBAAuB,EAEvB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC5B,MAAM,YAAY,CAAC;AAMpB,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,qFAAqF;AACrF,qBAAa,wBAAyB,SAAQ,KAAK;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,eAAe;gBAA/D,MAAM,EAAE,MAAM,EAAW,IAAI,EAAE,cAAc,GAAG,eAAe,EAAE,KAAK,EAAE,OAAO;CAIrG;AAED,qBAAa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;gBAE/B,SAAS,EAAE,uBAAuB,EAAE,EAAE,OAAO,GAAE,8BAAmC;IASxF,OAAO,CAAC,KAAK,EAAE;QACnB,OAAO,EAAE,sBAAsB,CAAC;QAChC,WAAW,EAAE,WAAW,CAAC;QACzB,QAAQ,EAAE,cAAc,EAAE,CAAC;QAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,sBAAsB,CAAC,EAAE,+BAA+B,CAAC,gBAAgB,CAAC,CAAC;KAC5E,GAAG,OAAO,CAAC,+BAA+B,CAAC;IAkC5C,YAAY,CAAC,YAAY,EAAE,2BAA2B,GAAG,MAAM;IAI/D,aAAa,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,OAAO;IAI3D,OAAO,CAAC,qBAAqB;IAS7B,aAAa,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,MAAM,GAAG,IAAI;IAIjE,OAAO,CAAC,WAAW;YAaL,gBAAgB;CAoC/B;AAED,wBAAgB,oCAAoC,CAAC,MAAM,EAAE,gBAAgB,GAAG,uBAAuB,CAMtG;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpE;AA6BD,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,oBAAoB,EAAE,EAC9B,QAAQ,SAAoB,GAC3B,2BAA2B,CA8B7B"}
|
|
@@ -1,51 +1,131 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { resolveThreadId } from "../../channels/interface.js";
|
|
3
3
|
import { logger } from "../../logger.js";
|
|
4
|
-
import { FinAppExternalContextProvider } from "./providers/finapp.js";
|
|
4
|
+
import { FinAppClientContextProvider, FinAppExternalContextProvider } from "./providers/finapp.js";
|
|
5
5
|
const DEFAULT_MAX_CHARS = 12_000;
|
|
6
6
|
const DEFAULT_PROVIDER_TIMEOUT_MS = 1_000;
|
|
7
|
+
/** Text hooks can contain mandatory contracts; never silently omit a failed hook. */
|
|
8
|
+
export class ExternalContextHookError extends Error {
|
|
9
|
+
source;
|
|
10
|
+
hook;
|
|
11
|
+
constructor(source, hook, cause) {
|
|
12
|
+
super(`External context provider ${source} ${hook} failed`, { cause });
|
|
13
|
+
this.source = source;
|
|
14
|
+
this.hook = hook;
|
|
15
|
+
this.name = "ExternalContextHookError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
7
18
|
export class ExternalContextRegistry {
|
|
8
19
|
providers;
|
|
9
20
|
maxChars;
|
|
10
21
|
providerTimeoutMs;
|
|
11
22
|
constructor(providers, options = {}) {
|
|
23
|
+
if (new Set(providers.map((provider) => provider.source)).size !== providers.length) {
|
|
24
|
+
throw new Error("External context provider sources must be unique");
|
|
25
|
+
}
|
|
12
26
|
this.providers = providers;
|
|
13
27
|
this.maxChars = options.maxChars ?? DEFAULT_MAX_CHARS;
|
|
14
28
|
this.providerTimeoutMs = options.providerTimeoutMs ?? DEFAULT_PROVIDER_TIMEOUT_MS;
|
|
15
29
|
}
|
|
16
30
|
async collect(input) {
|
|
17
|
-
const providerInput = normalizeProviderInput(input.trigger, input.sessionMode, input.messages);
|
|
18
|
-
const settled = await Promise.all(this.providers.map((provider) =>
|
|
19
|
-
|
|
31
|
+
const providerInput = { ...normalizeProviderInput(input.trigger, input.sessionMode, input.messages), interrupt: input.interrupt };
|
|
32
|
+
const settled = await Promise.all(this.providers.map(async (provider) => {
|
|
33
|
+
// Check validity at the moment of fallback: credentials may change while build awaits I/O.
|
|
34
|
+
const previous = () => {
|
|
35
|
+
const blocks = input.previousProviderBlocks?.get(provider.source) ?? [];
|
|
36
|
+
try {
|
|
37
|
+
return !provider.canReuseContext || provider.canReuseContext(providerInput, blocks) ? blocks : [];
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
logger.warn(`[external-context] provider ${provider.source} snapshot check failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
// An interrupt updates only the providers that own it. Others retain
|
|
45
|
+
// their wake-start context, even when this batch has no message for them.
|
|
46
|
+
const blocks = input.interrupt && !this.providerOwnsInterrupt(provider, input.messages)
|
|
47
|
+
? previous()
|
|
48
|
+
: await this.buildWithTimeout(provider, providerInput)
|
|
49
|
+
?? previous();
|
|
50
|
+
return [provider.source, blocks];
|
|
51
|
+
}));
|
|
52
|
+
const providerBlocks = new Map(settled);
|
|
53
|
+
const blocks = settled.flatMap(([, blocks]) => blocks).sort((a, b) => b.priority - a.priority || a.source.localeCompare(b.source));
|
|
20
54
|
const rendered = renderExternalContextBlocks(blocks, this.maxChars);
|
|
21
55
|
if (rendered.blocks.length > 0) {
|
|
22
56
|
logger.system(`external_context_injected sources=${JSON.stringify([...new Set(rendered.blocks.map((b) => b.source))])} threadId=${providerInput.threadId} digests=${JSON.stringify(rendered.blocks.map((b) => b.digest))} totalChars=${rendered.totalChars} truncated=${rendered.truncated}`);
|
|
23
57
|
}
|
|
24
|
-
return rendered;
|
|
58
|
+
return { ...rendered, providerBlocks };
|
|
59
|
+
}
|
|
60
|
+
systemPrompt(conversation) {
|
|
61
|
+
return this.collectText("systemPrompt", (provider) => provider.systemPrompt?.(conversation));
|
|
62
|
+
}
|
|
63
|
+
ownsInterrupt(messages) {
|
|
64
|
+
return this.providers.some((provider) => this.providerOwnsInterrupt(provider, messages));
|
|
65
|
+
}
|
|
66
|
+
providerOwnsInterrupt(provider, messages) {
|
|
67
|
+
try {
|
|
68
|
+
return provider.ownsInterrupt?.(messages) ?? false;
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
logger.warn(`[external-context] provider ${provider.source} interrupt check failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
interruptText(messages) {
|
|
76
|
+
return this.collectText("interruptText", (provider) => provider.interruptText?.(messages)) || null;
|
|
77
|
+
}
|
|
78
|
+
collectText(hook, read) {
|
|
79
|
+
return this.providers.map((provider) => {
|
|
80
|
+
try {
|
|
81
|
+
return read(provider)?.trim() ?? null;
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
throw new ExternalContextHookError(provider.source, hook, err);
|
|
85
|
+
}
|
|
86
|
+
}).filter((text) => Boolean(text)).join("\n\n");
|
|
25
87
|
}
|
|
26
88
|
async buildWithTimeout(provider, input) {
|
|
27
89
|
let timeout;
|
|
90
|
+
const controller = new AbortController();
|
|
28
91
|
try {
|
|
92
|
+
input = { ...input, signal: controller.signal };
|
|
93
|
+
if (provider.selectMessage) {
|
|
94
|
+
const primaryMessage = provider.selectMessage(input);
|
|
95
|
+
input = {
|
|
96
|
+
...input,
|
|
97
|
+
primaryMessage,
|
|
98
|
+
threadId: primaryMessage ? resolveThreadId(primaryMessage) : "default",
|
|
99
|
+
channel: primaryMessage?.channel ?? null,
|
|
100
|
+
channelMeta: primaryMessage?.meta ?? {},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
29
103
|
return await Promise.race([
|
|
30
104
|
provider.build(input),
|
|
31
105
|
new Promise((resolve) => {
|
|
32
|
-
timeout = setTimeout(() =>
|
|
106
|
+
timeout = setTimeout(() => {
|
|
107
|
+
logger.warn(`[external-context] provider ${provider.source} timed out`);
|
|
108
|
+
resolve(null);
|
|
109
|
+
}, this.providerTimeoutMs);
|
|
33
110
|
timeout.unref();
|
|
34
111
|
}),
|
|
35
112
|
]);
|
|
36
113
|
}
|
|
37
114
|
catch (err) {
|
|
38
115
|
logger.warn(`[external-context] provider ${provider.source} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
39
|
-
return
|
|
116
|
+
return null;
|
|
40
117
|
}
|
|
41
118
|
finally {
|
|
42
119
|
if (timeout)
|
|
43
120
|
clearTimeout(timeout);
|
|
121
|
+
controller.abort();
|
|
44
122
|
}
|
|
45
123
|
}
|
|
46
124
|
}
|
|
47
125
|
export function createDefaultExternalContextRegistry(config) {
|
|
126
|
+
// Other built-in integration hooks: channels/credential-backed.ts and event-trigger/wake-routing.ts.
|
|
48
127
|
return new ExternalContextRegistry([
|
|
128
|
+
new FinAppClientContextProvider(),
|
|
49
129
|
new FinAppExternalContextProvider(config),
|
|
50
130
|
]);
|
|
51
131
|
}
|
|
@@ -53,7 +133,7 @@ export function digestExternalContextContent(content) {
|
|
|
53
133
|
return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
54
134
|
}
|
|
55
135
|
function normalizeProviderInput(trigger, sessionMode, messages) {
|
|
56
|
-
const primaryMessage = messages.
|
|
136
|
+
const primaryMessage = messages.at(0);
|
|
57
137
|
if (!primaryMessage) {
|
|
58
138
|
return {
|
|
59
139
|
trigger,
|