@standardagents/builder 0.39.1 → 0.40.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/built-in-routes.js +609 -94
- package/dist/built-in-routes.js.map +1 -1
- package/dist/client/{ApiKeysView-AH5i-H6j.js → ApiKeysView-DoYvZZ7e.js} +1 -1
- package/dist/client/{CenteredContentView-DaBp0K-A.js → CenteredContentView-53PY0cqY.js} +1 -1
- package/dist/client/{CompositionView-yY1Q4M23.js → CompositionView-fp-0YnPt.js} +1 -1
- package/dist/client/{ConfirmDialog.vue_vue_type_script_setup_true_lang-Bwo5CJzF.js → ConfirmDialog.vue_vue_type_script_setup_true_lang-Cvcagja2.js} +1 -1
- package/dist/client/{CopyButton.vue_vue_type_script_setup_true_lang-D0WYwWyA.js → CopyButton.vue_vue_type_script_setup_true_lang-jYvO2v1K.js} +1 -1
- package/dist/client/{DataTable.vue_vue_type_script_setup_true_lang-1wwPn2aY.js → DataTable.vue_vue_type_script_setup_true_lang-DQ3Ufa7y.js} +1 -1
- package/dist/client/{JsonViewer-Bi8Zdmir.js → JsonViewer-6aaGzutE.js} +1 -1
- package/dist/client/{LoginView-BIKahEU6.js → LoginView-DwpCmNw9.js} +1 -1
- package/dist/client/{MarketplaceView-DPDPVH68.js → MarketplaceView-Da02L0J5.js} +1 -1
- package/dist/client/{Modal.vue_vue_type_script_setup_true_lang-D1_rfOsy.js → Modal.vue_vue_type_script_setup_true_lang-Bi8OjiBf.js} +1 -1
- package/dist/client/{ModelModal.vue_vue_type_script_setup_true_lang-DSLeOdxr.js → ModelModal.vue_vue_type_script_setup_true_lang-cYZLOYY7.js} +1 -1
- package/dist/client/{ModelsView-Q2WXu1Gw.js → ModelsView-BLlHO9Ud.js} +1 -1
- package/dist/client/{PromptEditView-BzA-3n1w.js → PromptEditView-EeNwTDtT.js} +1 -1
- package/dist/client/{PromptModal-CJWh_cru.js → PromptModal-BkwrKJ2d.js} +1 -1
- package/dist/client/{PromptsView-BezNl-Et.js → PromptsView-D1r7tsLu.js} +1 -1
- package/dist/client/{ProvidersView-BuzSKxuT.js → ProvidersView-CmUDl5nM.js} +1 -1
- package/dist/client/{ThreadInspectorPane.vue_vue_type_script_setup_true_lang-DOxNp_3C.js → ThreadInspectorPane.vue_vue_type_script_setup_true_lang-cRs3tApQ.js} +1 -1
- package/dist/client/{ThreadsView-DPCpZA4J.js → ThreadsView-Bl5fSIO1.js} +1 -1
- package/dist/client/{ToolsView-DMjFMAhH.js → ToolsView-DlVEF8-7.js} +1 -1
- package/dist/client/{UsersView-B7jXLNQs.js → UsersView-CGlA7a7R.js} +1 -1
- package/dist/client/{VariablesView-CF7x0G8g.js → VariablesView-BpYmJL4V.js} +1 -1
- package/dist/client/index-CKtIkI0N.js +6 -0
- package/dist/client/index.html +1 -1
- package/dist/{discovery-DiMJWisl.d.ts → discovery-DZ7fv-b4.d.ts} +3 -2
- package/dist/{index-yIcqf7DC.d.ts → index-0NI3m5DR.d.ts} +8 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1299 -758
- package/dist/index.js.map +1 -1
- package/dist/packing.d.ts +5 -3
- package/dist/packing.js +180 -5
- package/dist/packing.js.map +1 -1
- package/dist/plugin.d.ts +12 -1
- package/dist/plugin.js +299 -19
- package/dist/plugin.js.map +1 -1
- package/dist/runtime.d.ts +12 -5
- package/dist/runtime.js +1009 -750
- package/dist/runtime.js.map +1 -1
- package/dist/test.d.ts +2 -2
- package/dist/{types-Bpe7IANZ.d.ts → types-BMnBYNwn.d.ts} +3 -1
- package/package.json +5 -5
- package/dist/client/index-eGECJFYe.js +0 -6
package/dist/built-in-routes.js
CHANGED
|
@@ -6680,6 +6680,255 @@ var init_context = __esm({
|
|
|
6680
6680
|
}
|
|
6681
6681
|
});
|
|
6682
6682
|
|
|
6683
|
+
// src/packing/resolver.ts
|
|
6684
|
+
function parseQualifiedName(name15) {
|
|
6685
|
+
if (name15.startsWith("@")) {
|
|
6686
|
+
const firstSlash = name15.indexOf("/");
|
|
6687
|
+
if (firstSlash === -1) {
|
|
6688
|
+
return [null, name15];
|
|
6689
|
+
}
|
|
6690
|
+
const secondSlash = name15.indexOf("/", firstSlash + 1);
|
|
6691
|
+
if (secondSlash === -1) {
|
|
6692
|
+
return [null, name15];
|
|
6693
|
+
}
|
|
6694
|
+
return [name15.substring(0, secondSlash), name15.substring(secondSlash + 1)];
|
|
6695
|
+
}
|
|
6696
|
+
const separatorIndex = name15.indexOf("/");
|
|
6697
|
+
if (separatorIndex === -1) {
|
|
6698
|
+
return [null, name15];
|
|
6699
|
+
}
|
|
6700
|
+
return [name15.substring(0, separatorIndex), name15.substring(separatorIndex + 1)];
|
|
6701
|
+
}
|
|
6702
|
+
function qualifyName(packageId, shortName) {
|
|
6703
|
+
return `${packageId}/${shortName}`;
|
|
6704
|
+
}
|
|
6705
|
+
var init_resolver = __esm({
|
|
6706
|
+
"src/packing/resolver.ts"() {
|
|
6707
|
+
}
|
|
6708
|
+
});
|
|
6709
|
+
|
|
6710
|
+
// src/agents/ParentHookResolver.ts
|
|
6711
|
+
function packageOf(definition) {
|
|
6712
|
+
return definition?.__package ?? definition?._package;
|
|
6713
|
+
}
|
|
6714
|
+
function qualifyWithinPackage(name15, packageId) {
|
|
6715
|
+
if (!packageId || parseQualifiedName(name15)[0] !== null) {
|
|
6716
|
+
return name15;
|
|
6717
|
+
}
|
|
6718
|
+
return qualifyName(packageId, name15);
|
|
6719
|
+
}
|
|
6720
|
+
function promptHooks(prompt) {
|
|
6721
|
+
if (!prompt) return [];
|
|
6722
|
+
return Array.isArray(prompt.hooks) ? prompt.hooks : Array.isArray(prompt._hooks) ? prompt._hooks : [];
|
|
6723
|
+
}
|
|
6724
|
+
function promptTools(prompt) {
|
|
6725
|
+
if (!prompt) return [];
|
|
6726
|
+
return Array.isArray(prompt.tools) ? prompt.tools : Array.isArray(prompt._tools) ? prompt._tools : [];
|
|
6727
|
+
}
|
|
6728
|
+
function relationDescriptor(entry) {
|
|
6729
|
+
if (typeof entry === "string") {
|
|
6730
|
+
return {
|
|
6731
|
+
relationshipName: entry,
|
|
6732
|
+
implementingAgent: entry,
|
|
6733
|
+
explicitlyAgentShaped: false
|
|
6734
|
+
};
|
|
6735
|
+
}
|
|
6736
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
6737
|
+
return null;
|
|
6738
|
+
}
|
|
6739
|
+
const config = entry;
|
|
6740
|
+
if (typeof config.name !== "string" || !config.name) {
|
|
6741
|
+
return null;
|
|
6742
|
+
}
|
|
6743
|
+
const implementingAgent = typeof config.agent === "string" && config.agent ? config.agent : config.name;
|
|
6744
|
+
const explicitlyAgentShaped = "agent" in config || "blocking" in config || "resumable" in config || "immediate" in config || "parentCommunication" in config || "hidden" in config;
|
|
6745
|
+
return {
|
|
6746
|
+
relationshipName: config.name,
|
|
6747
|
+
implementingAgent,
|
|
6748
|
+
optional: typeof config.optional === "string" ? config.optional : void 0,
|
|
6749
|
+
explicitlyAgentShaped
|
|
6750
|
+
};
|
|
6751
|
+
}
|
|
6752
|
+
function hookLoader(host, owner, hookId) {
|
|
6753
|
+
const ownerPackage = packageOf(owner);
|
|
6754
|
+
if (!ownerPackage) {
|
|
6755
|
+
return host.hooks()[hookId];
|
|
6756
|
+
}
|
|
6757
|
+
return host.registry?.()?.packages?.[ownerPackage.packageId]?.hooks?.[hookId];
|
|
6758
|
+
}
|
|
6759
|
+
async function loadBinding(host, owner, hookId, hookType, context, required) {
|
|
6760
|
+
const loader = hookLoader(host, owner, hookId);
|
|
6761
|
+
if (!loader) {
|
|
6762
|
+
if (required) {
|
|
6763
|
+
throw new Error(
|
|
6764
|
+
`Required parent hook '${hookId}' was not found in the child agent namespace`
|
|
6765
|
+
);
|
|
6766
|
+
}
|
|
6767
|
+
return null;
|
|
6768
|
+
}
|
|
6769
|
+
let loaded;
|
|
6770
|
+
try {
|
|
6771
|
+
loaded = await loader();
|
|
6772
|
+
} catch (error) {
|
|
6773
|
+
if (required) throw error;
|
|
6774
|
+
console.error(`[Hooks] Failed to load hook '${hookId}':`, error);
|
|
6775
|
+
return null;
|
|
6776
|
+
}
|
|
6777
|
+
if (!loaded) {
|
|
6778
|
+
if (required) {
|
|
6779
|
+
throw new Error(`Required parent hook '${hookId}' did not export a hook definition`);
|
|
6780
|
+
}
|
|
6781
|
+
return null;
|
|
6782
|
+
}
|
|
6783
|
+
if (typeof loaded.id !== "string" || loaded.id !== hookId) {
|
|
6784
|
+
if (required) {
|
|
6785
|
+
throw new Error(`Required parent hook '${hookId}' exported a mismatched hook ID`);
|
|
6786
|
+
}
|
|
6787
|
+
return null;
|
|
6788
|
+
}
|
|
6789
|
+
if (typeof loaded.execute !== "function") {
|
|
6790
|
+
if (required) {
|
|
6791
|
+
throw new Error(`Required parent hook '${hookId}' did not export an execute function`);
|
|
6792
|
+
}
|
|
6793
|
+
return null;
|
|
6794
|
+
}
|
|
6795
|
+
if (USER_HOOK_NAMES.has(loaded.hook)) {
|
|
6796
|
+
if (required) {
|
|
6797
|
+
throw new Error(
|
|
6798
|
+
`Required parent hook '${hookId}' uses user-scoped hook type '${loaded.hook}'`
|
|
6799
|
+
);
|
|
6800
|
+
}
|
|
6801
|
+
return null;
|
|
6802
|
+
}
|
|
6803
|
+
if (!THREAD_HOOK_NAMES.has(loaded.hook)) {
|
|
6804
|
+
if (required) {
|
|
6805
|
+
throw new Error(`Required parent hook '${hookId}' exported invalid hook type '${loaded.hook}'`);
|
|
6806
|
+
}
|
|
6807
|
+
return null;
|
|
6808
|
+
}
|
|
6809
|
+
if (loaded.hook !== hookType) {
|
|
6810
|
+
return null;
|
|
6811
|
+
}
|
|
6812
|
+
return {
|
|
6813
|
+
id: hookId,
|
|
6814
|
+
hook: hookType,
|
|
6815
|
+
execute: loaded.execute,
|
|
6816
|
+
context
|
|
6817
|
+
};
|
|
6818
|
+
}
|
|
6819
|
+
async function resolveHooksForPrompt(input, hookType) {
|
|
6820
|
+
const agent = input.agent ?? await input.host.loadAgent(input.agentName);
|
|
6821
|
+
const agentPackage = packageOf(agent);
|
|
6822
|
+
const unqualifiedPromptName = input.promptName ?? agent.sideA?.prompt;
|
|
6823
|
+
const resolvedPromptName = unqualifiedPromptName ? qualifyWithinPackage(unqualifiedPromptName, agentPackage?.packageId) : void 0;
|
|
6824
|
+
const prompt = input.prompt ?? (resolvedPromptName ? await input.host.loadPrompt(resolvedPromptName) : void 0);
|
|
6825
|
+
const promptName = prompt?.name ?? prompt?.id ?? resolvedPromptName ?? "unknown_prompt";
|
|
6826
|
+
const before = [];
|
|
6827
|
+
const after = [];
|
|
6828
|
+
for (const entry of promptTools(prompt)) {
|
|
6829
|
+
const relation = relationDescriptor(entry);
|
|
6830
|
+
if (!relation) continue;
|
|
6831
|
+
if (relation.optional && input.isOptionalRelationshipEnabled && !await input.isOptionalRelationshipEnabled(relation.optional)) {
|
|
6832
|
+
continue;
|
|
6833
|
+
}
|
|
6834
|
+
const promptPackage = packageOf(prompt) ?? agentPackage;
|
|
6835
|
+
const childReference = qualifyWithinPackage(
|
|
6836
|
+
relation.implementingAgent,
|
|
6837
|
+
promptPackage?.packageId
|
|
6838
|
+
);
|
|
6839
|
+
let child;
|
|
6840
|
+
try {
|
|
6841
|
+
child = await input.host.loadAgent(childReference);
|
|
6842
|
+
} catch (error) {
|
|
6843
|
+
if (relation.explicitlyAgentShaped) throw error;
|
|
6844
|
+
continue;
|
|
6845
|
+
}
|
|
6846
|
+
if (child.type !== "dual_ai") continue;
|
|
6847
|
+
if (child.parentHooks !== void 0 && child.exposeAsTool !== true) {
|
|
6848
|
+
throw new Error(
|
|
6849
|
+
`Child agent '${childReference}' declares parentHooks but is not exposed as a tool`
|
|
6850
|
+
);
|
|
6851
|
+
}
|
|
6852
|
+
if (child.parentHooks !== void 0 && !Array.isArray(child.parentHooks)) {
|
|
6853
|
+
throw new Error(`Child agent '${childReference}' has an invalid parentHooks declaration`);
|
|
6854
|
+
}
|
|
6855
|
+
const requirements = child.parentHooks ?? [];
|
|
6856
|
+
const seenRequirements = /* @__PURE__ */ new Set();
|
|
6857
|
+
for (const requirement of requirements) {
|
|
6858
|
+
if (!requirement || typeof requirement !== "object" || typeof requirement.hook !== "string" || !requirement.hook || typeof requirement.reason !== "string" || !requirement.reason.trim() || requirement.stage !== void 0 && requirement.stage !== "before_parent" && requirement.stage !== "after_parent" || seenRequirements.has(requirement.hook)) {
|
|
6859
|
+
throw new Error(`Child agent '${childReference}' has an invalid parentHooks requirement`);
|
|
6860
|
+
}
|
|
6861
|
+
seenRequirements.add(requirement.hook);
|
|
6862
|
+
const loaded = await loadBinding(
|
|
6863
|
+
input.host,
|
|
6864
|
+
child,
|
|
6865
|
+
requirement.hook,
|
|
6866
|
+
hookType,
|
|
6867
|
+
{
|
|
6868
|
+
source: {
|
|
6869
|
+
kind: "child",
|
|
6870
|
+
relationshipName: relation.relationshipName,
|
|
6871
|
+
agentName: childReference,
|
|
6872
|
+
package: packageOf(child)
|
|
6873
|
+
}
|
|
6874
|
+
},
|
|
6875
|
+
true
|
|
6876
|
+
);
|
|
6877
|
+
if (!loaded) continue;
|
|
6878
|
+
if ((requirement.stage ?? "after_parent") === "before_parent") {
|
|
6879
|
+
before.push(loaded);
|
|
6880
|
+
} else {
|
|
6881
|
+
after.push(loaded);
|
|
6882
|
+
}
|
|
6883
|
+
}
|
|
6884
|
+
}
|
|
6885
|
+
const promptHookIds = promptHooks(prompt);
|
|
6886
|
+
const promptOwnsBaseHooks = promptHookIds.length > 0 && prompt !== void 0;
|
|
6887
|
+
const baseOwner = promptOwnsBaseHooks ? prompt : agent;
|
|
6888
|
+
const baseIds = promptHookIds.length > 0 ? promptHookIds : Array.isArray(agent.hooks) ? agent.hooks : [];
|
|
6889
|
+
const baseContext = promptOwnsBaseHooks ? { source: { kind: "prompt", promptName } } : { source: { kind: "agent", agentName: input.agentName } };
|
|
6890
|
+
const base = [];
|
|
6891
|
+
for (const hookId of baseIds) {
|
|
6892
|
+
const loaded = await loadBinding(
|
|
6893
|
+
input.host,
|
|
6894
|
+
baseOwner,
|
|
6895
|
+
hookId,
|
|
6896
|
+
hookType,
|
|
6897
|
+
baseContext,
|
|
6898
|
+
false
|
|
6899
|
+
);
|
|
6900
|
+
if (loaded) base.push(loaded);
|
|
6901
|
+
}
|
|
6902
|
+
return [...before, ...base, ...after];
|
|
6903
|
+
}
|
|
6904
|
+
var USER_HOOK_NAMES, THREAD_HOOK_NAMES;
|
|
6905
|
+
var init_ParentHookResolver = __esm({
|
|
6906
|
+
"src/agents/ParentHookResolver.ts"() {
|
|
6907
|
+
init_resolver();
|
|
6908
|
+
USER_HOOK_NAMES = /* @__PURE__ */ new Set([
|
|
6909
|
+
"user_client_attached",
|
|
6910
|
+
"user_client_detached",
|
|
6911
|
+
"user_value_changed"
|
|
6912
|
+
]);
|
|
6913
|
+
THREAD_HOOK_NAMES = /* @__PURE__ */ new Set([
|
|
6914
|
+
"after_thread_created",
|
|
6915
|
+
"after_subagent_created",
|
|
6916
|
+
"after_system_message",
|
|
6917
|
+
"filter_messages",
|
|
6918
|
+
"prefilter_llm_history",
|
|
6919
|
+
"before_create_message",
|
|
6920
|
+
"after_create_message",
|
|
6921
|
+
"before_update_message",
|
|
6922
|
+
"after_update_message",
|
|
6923
|
+
"before_store_tool_result",
|
|
6924
|
+
"after_tool_call_success",
|
|
6925
|
+
"after_tool_call_failure",
|
|
6926
|
+
"tool_call_started",
|
|
6927
|
+
"tool_call_done"
|
|
6928
|
+
]);
|
|
6929
|
+
}
|
|
6930
|
+
});
|
|
6931
|
+
|
|
6683
6932
|
// src/agents/FlowEngine.ts
|
|
6684
6933
|
var FlowEngine_exports = {};
|
|
6685
6934
|
__export(FlowEngine_exports, {
|
|
@@ -6696,6 +6945,7 @@ var init_FlowEngine = __esm({
|
|
|
6696
6945
|
init_context();
|
|
6697
6946
|
init_sessionTools();
|
|
6698
6947
|
init_ThreadStateImpl();
|
|
6948
|
+
init_ParentHookResolver();
|
|
6699
6949
|
IMMEDIATE_BOOTSTRAP_TOOL_NAME = "bootstrap_immediate_subagent";
|
|
6700
6950
|
HookBlockedExecutionError = class extends Error {
|
|
6701
6951
|
constructor(message) {
|
|
@@ -7038,7 +7288,8 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
7038
7288
|
_variables: def.variables ?? [],
|
|
7039
7289
|
_env: def.env ?? def.tenvs ?? {},
|
|
7040
7290
|
_requiredSchema: def.requiredSchema ?? null,
|
|
7041
|
-
_hooks: def.hooks ?? []
|
|
7291
|
+
_hooks: def.hooks ?? [],
|
|
7292
|
+
_package: def.__package
|
|
7042
7293
|
};
|
|
7043
7294
|
}
|
|
7044
7295
|
/**
|
|
@@ -7428,6 +7679,8 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
7428
7679
|
type: newAgentDef.type,
|
|
7429
7680
|
created_at: Date.now(),
|
|
7430
7681
|
max_session_turns: newAgentDef.maxSessionTurns ?? null,
|
|
7682
|
+
hooks: newAgentDef.hooks ?? [],
|
|
7683
|
+
_package: newAgentDef.__package,
|
|
7431
7684
|
side_a_label: newAgentDef.sideA?.label ?? null,
|
|
7432
7685
|
side_a_agent_prompt: newAgentDef.sideA?.prompt ?? null,
|
|
7433
7686
|
side_a_stop_on_response: newAgentDef.sideA?.stopOnResponse ?? true,
|
|
@@ -7588,7 +7841,7 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
7588
7841
|
return null;
|
|
7589
7842
|
}
|
|
7590
7843
|
return await stub.resolveThreadEnv({
|
|
7591
|
-
threadId: state.
|
|
7844
|
+
threadId: state.thread.metadata.id,
|
|
7592
7845
|
property,
|
|
7593
7846
|
promptName: state.prompt?.name
|
|
7594
7847
|
});
|
|
@@ -8110,8 +8363,8 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
8110
8363
|
state.context[key] = existing;
|
|
8111
8364
|
}
|
|
8112
8365
|
static async runImmediateToolsIfNeeded(state) {
|
|
8113
|
-
const
|
|
8114
|
-
if (
|
|
8366
|
+
const promptTools2 = Array.isArray(state.prompt._tools) ? state.prompt._tools : [];
|
|
8367
|
+
if (promptTools2.length === 0) {
|
|
8115
8368
|
return false;
|
|
8116
8369
|
}
|
|
8117
8370
|
if (!state.immediatePromptRuns) {
|
|
@@ -8147,7 +8400,7 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
8147
8400
|
(activeInstanceCounts.get(child.name) ?? 0) + 1
|
|
8148
8401
|
);
|
|
8149
8402
|
}
|
|
8150
|
-
for (const toolConfig of
|
|
8403
|
+
for (const toolConfig of promptTools2) {
|
|
8151
8404
|
if (!toolConfig || typeof toolConfig !== "object") {
|
|
8152
8405
|
continue;
|
|
8153
8406
|
}
|
|
@@ -8313,10 +8566,10 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
8313
8566
|
* model's to clean up, and terminate_subagent on an infrastructure child
|
|
8314
8567
|
* kills work the runtime depends on. Static and pure for direct testing.
|
|
8315
8568
|
*/
|
|
8316
|
-
static filterModelVisibleSubagents(registry,
|
|
8569
|
+
static filterModelVisibleSubagents(registry, promptTools2) {
|
|
8317
8570
|
if (registry.length === 0) return registry;
|
|
8318
8571
|
const hidden = /* @__PURE__ */ new Set();
|
|
8319
|
-
for (const config of
|
|
8572
|
+
for (const config of promptTools2 ?? []) {
|
|
8320
8573
|
if (typeof config === "object" && config !== null && "name" in config && config.hidden === true) {
|
|
8321
8574
|
hidden.add(config.name);
|
|
8322
8575
|
}
|
|
@@ -9346,8 +9599,8 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9346
9599
|
try {
|
|
9347
9600
|
const nativeTools = await this.loadNativeTools(state);
|
|
9348
9601
|
tools.push(...nativeTools);
|
|
9349
|
-
const
|
|
9350
|
-
tools.push(...
|
|
9602
|
+
const promptTools2 = await this.loadPromptTools(state);
|
|
9603
|
+
tools.push(...promptTools2);
|
|
9351
9604
|
const agentTools = await this.loadAgentTools(state);
|
|
9352
9605
|
tools.push(...agentTools);
|
|
9353
9606
|
const toolNameSources = /* @__PURE__ */ new Map();
|
|
@@ -9356,7 +9609,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9356
9609
|
sources.add("native tool");
|
|
9357
9610
|
toolNameSources.set(tool3.function.name, sources);
|
|
9358
9611
|
}
|
|
9359
|
-
for (const tool3 of
|
|
9612
|
+
for (const tool3 of promptTools2) {
|
|
9360
9613
|
const sources = toolNameSources.get(tool3.function.name) || /* @__PURE__ */ new Set();
|
|
9361
9614
|
sources.add("prompt");
|
|
9362
9615
|
toolNameSources.set(tool3.function.name, sources);
|
|
@@ -9498,24 +9751,8 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9498
9751
|
// Hook Resolution Helpers
|
|
9499
9752
|
// ==========================================================================
|
|
9500
9753
|
/**
|
|
9501
|
-
*
|
|
9502
|
-
*
|
|
9503
|
-
*
|
|
9504
|
-
* @param state - Flow state with prompt and agent configuration
|
|
9505
|
-
* @returns Array of hook IDs to execute
|
|
9506
|
-
*/
|
|
9507
|
-
static getActiveHookIds(state) {
|
|
9508
|
-
if (state.prompt?._hooks !== void 0 && state.prompt._hooks.length > 0) {
|
|
9509
|
-
return state.prompt._hooks;
|
|
9510
|
-
}
|
|
9511
|
-
if (state.agentConfig.hooks !== void 0 && state.agentConfig.hooks.length > 0) {
|
|
9512
|
-
return state.agentConfig.hooks;
|
|
9513
|
-
}
|
|
9514
|
-
return [];
|
|
9515
|
-
}
|
|
9516
|
-
/**
|
|
9517
|
-
* Get hooks of a specific type from the active hook IDs.
|
|
9518
|
-
* Returns typed hook executors in the order they appear in the hooks array.
|
|
9754
|
+
* Resolve hooks of a specific type for the active prompt, including required
|
|
9755
|
+
* hooks contributed automatically by its enabled direct child agents.
|
|
9519
9756
|
*
|
|
9520
9757
|
* @template K - The hook type name (ensures type-safe executors)
|
|
9521
9758
|
* @param state - Flow state with hook configuration
|
|
@@ -9523,24 +9760,17 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9523
9760
|
* @returns Array of typed hook executor functions
|
|
9524
9761
|
*/
|
|
9525
9762
|
static async getHooksForType(state, hookType) {
|
|
9526
|
-
|
|
9527
|
-
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
|
|
9537
|
-
executors.push(hookDef.execute);
|
|
9538
|
-
}
|
|
9539
|
-
} catch (error) {
|
|
9540
|
-
console.error(`[Hooks] Failed to load hook '${hookId}':`, error);
|
|
9541
|
-
}
|
|
9542
|
-
}
|
|
9543
|
-
return executors;
|
|
9763
|
+
return await resolveHooksForPrompt(
|
|
9764
|
+
{
|
|
9765
|
+
host: state.thread.instance,
|
|
9766
|
+
agentName: state.agentConfig.id,
|
|
9767
|
+
agent: state.agentConfig,
|
|
9768
|
+
promptName: state.prompt?.id,
|
|
9769
|
+
prompt: state.prompt,
|
|
9770
|
+
isOptionalRelationshipEnabled: (envName) => this.isOptionalToolEnabled(state, envName)
|
|
9771
|
+
},
|
|
9772
|
+
hookType
|
|
9773
|
+
);
|
|
9544
9774
|
}
|
|
9545
9775
|
// ==========================================================================
|
|
9546
9776
|
// Hook Runner Methods
|
|
@@ -9558,9 +9788,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9558
9788
|
if (executors.length === 0) return messages;
|
|
9559
9789
|
let result = messages;
|
|
9560
9790
|
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9561
|
-
for (const
|
|
9791
|
+
for (const { execute, context } of executors) {
|
|
9562
9792
|
try {
|
|
9563
|
-
result = await
|
|
9793
|
+
result = await execute(threadState, result, context);
|
|
9564
9794
|
} catch (error) {
|
|
9565
9795
|
if (error && typeof error === "object" && error.block === true) {
|
|
9566
9796
|
throw new HookBlockedExecutionError(error instanceof Error ? error.message : String(error));
|
|
@@ -9578,9 +9808,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9578
9808
|
if (executors.length === 0) return systemMessage;
|
|
9579
9809
|
let result = systemMessage;
|
|
9580
9810
|
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9581
|
-
for (const
|
|
9811
|
+
for (const { execute, context } of executors) {
|
|
9582
9812
|
try {
|
|
9583
|
-
const next = await
|
|
9813
|
+
const next = await execute(threadState, result, context);
|
|
9584
9814
|
if (next !== null && next !== void 0) {
|
|
9585
9815
|
result = next;
|
|
9586
9816
|
}
|
|
@@ -9597,9 +9827,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9597
9827
|
const executors = await this.getHooksForType(state, "after_subagent_created");
|
|
9598
9828
|
if (executors.length === 0) return;
|
|
9599
9829
|
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9600
|
-
for (const
|
|
9830
|
+
for (const { execute, context } of executors) {
|
|
9601
9831
|
try {
|
|
9602
|
-
await
|
|
9832
|
+
await execute(threadState, childState, context);
|
|
9603
9833
|
} catch (error) {
|
|
9604
9834
|
console.error("[Hooks] \u2717 Error running after_subagent_created hook:", error);
|
|
9605
9835
|
}
|
|
@@ -9618,9 +9848,13 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9618
9848
|
if (executors.length === 0) return message;
|
|
9619
9849
|
let result = message;
|
|
9620
9850
|
const threadState = threadStateOverride ?? ThreadStateImpl.fromFlowState(state);
|
|
9621
|
-
for (const
|
|
9851
|
+
for (const { execute, context } of executors) {
|
|
9622
9852
|
try {
|
|
9623
|
-
const hooked = await
|
|
9853
|
+
const hooked = await execute(
|
|
9854
|
+
threadState,
|
|
9855
|
+
_FlowEngine.rowToHookMessage(result),
|
|
9856
|
+
context
|
|
9857
|
+
);
|
|
9624
9858
|
result = {
|
|
9625
9859
|
...result,
|
|
9626
9860
|
...hooked,
|
|
@@ -9646,9 +9880,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9646
9880
|
const executors = await this.getHooksForType(state, "after_create_message");
|
|
9647
9881
|
if (executors.length === 0) return;
|
|
9648
9882
|
const threadState = threadStateOverride ?? ThreadStateImpl.fromFlowState(state);
|
|
9649
|
-
for (const
|
|
9883
|
+
for (const { execute, context } of executors) {
|
|
9650
9884
|
try {
|
|
9651
|
-
await
|
|
9885
|
+
await execute(threadState, _FlowEngine.rowToHookMessage(message), context);
|
|
9652
9886
|
} catch (error) {
|
|
9653
9887
|
console.error("[Hooks] \u2717 Error running after_create_message hook:", error);
|
|
9654
9888
|
}
|
|
@@ -9689,9 +9923,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9689
9923
|
if (executors.length === 0) return updates;
|
|
9690
9924
|
let result = updates;
|
|
9691
9925
|
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9692
|
-
for (const
|
|
9926
|
+
for (const { execute, context } of executors) {
|
|
9693
9927
|
try {
|
|
9694
|
-
result = await
|
|
9928
|
+
result = await execute(threadState, messageId, result, context);
|
|
9695
9929
|
} catch (error) {
|
|
9696
9930
|
console.error("[Hooks] \u2717 Error running before_update_message hook:", error);
|
|
9697
9931
|
}
|
|
@@ -9709,9 +9943,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9709
9943
|
const executors = await this.getHooksForType(state, "after_update_message");
|
|
9710
9944
|
if (executors.length === 0) return;
|
|
9711
9945
|
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9712
|
-
for (const
|
|
9946
|
+
for (const { execute, context } of executors) {
|
|
9713
9947
|
try {
|
|
9714
|
-
await
|
|
9948
|
+
await execute(threadState, _FlowEngine.rowToHookMessage(message), context);
|
|
9715
9949
|
} catch (error) {
|
|
9716
9950
|
console.error("[Hooks] \u2717 Error running after_update_message hook:", error);
|
|
9717
9951
|
}
|
|
@@ -9731,9 +9965,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9731
9965
|
if (executors.length === 0) return toolResult;
|
|
9732
9966
|
let result = toolResult;
|
|
9733
9967
|
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9734
|
-
for (const
|
|
9968
|
+
for (const { execute, context } of executors) {
|
|
9735
9969
|
try {
|
|
9736
|
-
result = await
|
|
9970
|
+
result = await execute(threadState, toolCall, result, context);
|
|
9737
9971
|
} catch (error) {
|
|
9738
9972
|
console.error("[Hooks] \u2717 Error running before_store_tool_result hook:", error);
|
|
9739
9973
|
}
|
|
@@ -9753,10 +9987,10 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9753
9987
|
if (executors.length === 0) return toolResult;
|
|
9754
9988
|
let result = toolResult;
|
|
9755
9989
|
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9756
|
-
for (const
|
|
9990
|
+
for (const { execute, context } of executors) {
|
|
9757
9991
|
if (result === null) break;
|
|
9758
9992
|
try {
|
|
9759
|
-
result = await
|
|
9993
|
+
result = await execute(threadState, toolCall, result, context);
|
|
9760
9994
|
} catch (error) {
|
|
9761
9995
|
console.error("[Hooks] \u2717 Error running after_tool_call_success hook:", error);
|
|
9762
9996
|
}
|
|
@@ -9776,10 +10010,10 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9776
10010
|
if (executors.length === 0) return toolResult;
|
|
9777
10011
|
let result = toolResult;
|
|
9778
10012
|
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9779
|
-
for (const
|
|
10013
|
+
for (const { execute, context } of executors) {
|
|
9780
10014
|
if (result === null) break;
|
|
9781
10015
|
try {
|
|
9782
|
-
result = await
|
|
10016
|
+
result = await execute(threadState, toolCall, result, context);
|
|
9783
10017
|
} catch (error) {
|
|
9784
10018
|
console.error("[Hooks] \u2717 Error running after_tool_call_failure hook:", error);
|
|
9785
10019
|
}
|
|
@@ -9809,9 +10043,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9809
10043
|
const executors = await this.getHooksForType(state, "tool_call_started");
|
|
9810
10044
|
if (executors.length === 0) return;
|
|
9811
10045
|
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9812
|
-
for (const
|
|
10046
|
+
for (const { execute, context } of executors) {
|
|
9813
10047
|
try {
|
|
9814
|
-
await
|
|
10048
|
+
await execute(threadState, toolCall, progress, context);
|
|
9815
10049
|
} catch (error) {
|
|
9816
10050
|
console.error("[Hooks] \u2717 Error running tool_call_started hook:", error);
|
|
9817
10051
|
}
|
|
@@ -9839,9 +10073,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9839
10073
|
const executors = await this.getHooksForType(state, "tool_call_done");
|
|
9840
10074
|
if (executors.length === 0) return;
|
|
9841
10075
|
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9842
|
-
for (const
|
|
10076
|
+
for (const { execute, context } of executors) {
|
|
9843
10077
|
try {
|
|
9844
|
-
await
|
|
10078
|
+
await execute(threadState, toolCall, toolResult, context);
|
|
9845
10079
|
} catch (error) {
|
|
9846
10080
|
console.error("[Hooks] \u2717 Error running tool_call_done hook:", error);
|
|
9847
10081
|
}
|
|
@@ -10794,12 +11028,12 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10794
11028
|
if (executors.length === 0) return messages;
|
|
10795
11029
|
let result = messages;
|
|
10796
11030
|
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
10797
|
-
for (const
|
|
11031
|
+
for (const { execute, context } of executors) {
|
|
10798
11032
|
try {
|
|
10799
11033
|
const byId = /* @__PURE__ */ new Map();
|
|
10800
11034
|
for (const row of result) if (row.id) byId.set(row.id, row);
|
|
10801
11035
|
const hookView = result.map((row) => _FlowEngine.rowToHookMessage(row));
|
|
10802
|
-
const kept = await
|
|
11036
|
+
const kept = await execute(threadState, hookView, context);
|
|
10803
11037
|
result = kept.map((hookedMessage) => {
|
|
10804
11038
|
const original = hookedMessage.id ? byId.get(hookedMessage.id) : void 0;
|
|
10805
11039
|
if (original) {
|
|
@@ -11017,7 +11251,12 @@ function queueTool(flow, toolName, args = {}) {
|
|
|
11017
11251
|
}
|
|
11018
11252
|
async function injectMessage(flow, options) {
|
|
11019
11253
|
const messageId = options.id ?? crypto.randomUUID();
|
|
11020
|
-
const
|
|
11254
|
+
const wallClockTimestamp = Date.now() * TIMESTAMP_MULTIPLIER;
|
|
11255
|
+
const latestLiveTimestamp = flow.messageHistory.reduce(
|
|
11256
|
+
(latest, entry) => Math.max(latest, entry.created_at),
|
|
11257
|
+
0
|
|
11258
|
+
);
|
|
11259
|
+
const timestamp = options.beforeMessageId ? wallClockTimestamp : Math.max(wallClockTimestamp, latestLiveTimestamp + 1);
|
|
11021
11260
|
const silent = options.silent ?? false;
|
|
11022
11261
|
const forceTopLevel = options.forceTopLevel ?? false;
|
|
11023
11262
|
let message = {
|
|
@@ -14803,11 +15042,19 @@ async function extractPromptTools(sourceCode) {
|
|
|
14803
15042
|
result.tools.push(element.text);
|
|
14804
15043
|
} else if (ts.isObjectLiteralExpression(element)) {
|
|
14805
15044
|
result.hasSubpromptConfigs = true;
|
|
15045
|
+
let configuredName;
|
|
15046
|
+
let implementingAgent;
|
|
14806
15047
|
for (const objProp of element.properties) {
|
|
14807
|
-
if (ts.isPropertyAssignment(objProp) && ts.isIdentifier(objProp.name) &&
|
|
14808
|
-
|
|
15048
|
+
if (ts.isPropertyAssignment(objProp) && ts.isIdentifier(objProp.name) && ts.isStringLiteral(objProp.initializer)) {
|
|
15049
|
+
if (objProp.name.text === "name") {
|
|
15050
|
+
configuredName = objProp.initializer.text;
|
|
15051
|
+
} else if (objProp.name.text === "agent") {
|
|
15052
|
+
implementingAgent = objProp.initializer.text;
|
|
15053
|
+
}
|
|
14809
15054
|
}
|
|
14810
15055
|
}
|
|
15056
|
+
const dependencyName = implementingAgent ?? configuredName;
|
|
15057
|
+
if (dependencyName) result.tools.push(dependencyName);
|
|
14811
15058
|
}
|
|
14812
15059
|
}
|
|
14813
15060
|
}
|
|
@@ -14930,6 +15177,106 @@ async function extractAgentPrompts(sourceCode) {
|
|
|
14930
15177
|
visit2(sourceFile);
|
|
14931
15178
|
return result;
|
|
14932
15179
|
}
|
|
15180
|
+
async function extractAgentHooks(sourceCode) {
|
|
15181
|
+
const ts = await loadTypeScript();
|
|
15182
|
+
const sourceFile = ts.createSourceFile(
|
|
15183
|
+
"agent.ts",
|
|
15184
|
+
sourceCode,
|
|
15185
|
+
ts.ScriptTarget.ESNext,
|
|
15186
|
+
true
|
|
15187
|
+
);
|
|
15188
|
+
const arrays = /* @__PURE__ */ new Map();
|
|
15189
|
+
const result = {
|
|
15190
|
+
hooks: [],
|
|
15191
|
+
parentHooks: [],
|
|
15192
|
+
parentHookRequirements: []
|
|
15193
|
+
};
|
|
15194
|
+
const unwrapArray = (expression) => {
|
|
15195
|
+
let current = expression;
|
|
15196
|
+
while (ts.isParenthesizedExpression(current) || ts.isAsExpression(current) || ts.isSatisfiesExpression(current)) {
|
|
15197
|
+
current = current.expression;
|
|
15198
|
+
}
|
|
15199
|
+
if (ts.isArrayLiteralExpression(current)) return current;
|
|
15200
|
+
if (ts.isIdentifier(current)) return arrays.get(current.text) ?? null;
|
|
15201
|
+
return null;
|
|
15202
|
+
};
|
|
15203
|
+
for (const statement of sourceFile.statements) {
|
|
15204
|
+
if (!ts.isVariableStatement(statement)) continue;
|
|
15205
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
15206
|
+
if (ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
15207
|
+
const array44 = unwrapArray(declaration.initializer);
|
|
15208
|
+
if (array44) arrays.set(declaration.name.text, array44);
|
|
15209
|
+
}
|
|
15210
|
+
}
|
|
15211
|
+
}
|
|
15212
|
+
const pushUnique = (target, value) => {
|
|
15213
|
+
if (!target.includes(value)) target.push(value);
|
|
15214
|
+
};
|
|
15215
|
+
function visit2(node) {
|
|
15216
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "defineAgent" && node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
|
|
15217
|
+
for (const property of node.arguments[0].properties) {
|
|
15218
|
+
if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name)) continue;
|
|
15219
|
+
const array44 = unwrapArray(property.initializer);
|
|
15220
|
+
if (!array44) continue;
|
|
15221
|
+
if (property.name.text === "hooks") {
|
|
15222
|
+
for (const element of array44.elements) {
|
|
15223
|
+
if (ts.isStringLiteral(element)) pushUnique(result.hooks, element.text);
|
|
15224
|
+
}
|
|
15225
|
+
}
|
|
15226
|
+
if (property.name.text === "parentHooks") {
|
|
15227
|
+
for (const element of array44.elements) {
|
|
15228
|
+
if (!ts.isObjectLiteralExpression(element)) continue;
|
|
15229
|
+
let hook;
|
|
15230
|
+
let reason;
|
|
15231
|
+
let stage;
|
|
15232
|
+
for (const requirement of element.properties) {
|
|
15233
|
+
if (ts.isPropertyAssignment(requirement) && ts.isIdentifier(requirement.name) && ts.isStringLiteral(requirement.initializer)) {
|
|
15234
|
+
if (requirement.name.text === "hook") hook = requirement.initializer.text;
|
|
15235
|
+
if (requirement.name.text === "reason") reason = requirement.initializer.text;
|
|
15236
|
+
if (requirement.name.text === "stage" && (requirement.initializer.text === "before_parent" || requirement.initializer.text === "after_parent")) {
|
|
15237
|
+
stage = requirement.initializer.text;
|
|
15238
|
+
}
|
|
15239
|
+
}
|
|
15240
|
+
}
|
|
15241
|
+
if (hook) {
|
|
15242
|
+
pushUnique(result.parentHooks, hook);
|
|
15243
|
+
if (reason) result.parentHookRequirements.push({ hook, reason, stage });
|
|
15244
|
+
}
|
|
15245
|
+
}
|
|
15246
|
+
}
|
|
15247
|
+
}
|
|
15248
|
+
}
|
|
15249
|
+
ts.forEachChild(node, visit2);
|
|
15250
|
+
}
|
|
15251
|
+
visit2(sourceFile);
|
|
15252
|
+
return result;
|
|
15253
|
+
}
|
|
15254
|
+
async function extractPromptHooks(sourceCode) {
|
|
15255
|
+
const ts = await loadTypeScript();
|
|
15256
|
+
const sourceFile = ts.createSourceFile(
|
|
15257
|
+
"prompt.ts",
|
|
15258
|
+
sourceCode,
|
|
15259
|
+
ts.ScriptTarget.ESNext,
|
|
15260
|
+
true
|
|
15261
|
+
);
|
|
15262
|
+
const hooks = [];
|
|
15263
|
+
function visit2(node) {
|
|
15264
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "definePrompt" && node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
|
|
15265
|
+
for (const property of node.arguments[0].properties) {
|
|
15266
|
+
if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && property.name.text === "hooks" && ts.isArrayLiteralExpression(property.initializer)) {
|
|
15267
|
+
for (const element of property.initializer.elements) {
|
|
15268
|
+
if (ts.isStringLiteral(element) && !hooks.includes(element.text)) {
|
|
15269
|
+
hooks.push(element.text);
|
|
15270
|
+
}
|
|
15271
|
+
}
|
|
15272
|
+
}
|
|
15273
|
+
}
|
|
15274
|
+
}
|
|
15275
|
+
ts.forEachChild(node, visit2);
|
|
15276
|
+
}
|
|
15277
|
+
visit2(sourceFile);
|
|
15278
|
+
return hooks;
|
|
15279
|
+
}
|
|
14933
15280
|
async function extractAgentDescription(sourceCode) {
|
|
14934
15281
|
const ts = await loadTypeScript();
|
|
14935
15282
|
const sourceFile = ts.createSourceFile(
|
|
@@ -15185,6 +15532,13 @@ var init_packing_service = __esm({
|
|
|
15185
15532
|
});
|
|
15186
15533
|
const agentSource = fs4.readFileSync(agentFilePath, "utf-8");
|
|
15187
15534
|
const agentPrompts = await extractAgentPrompts(agentSource);
|
|
15535
|
+
const agentHooks = await extractAgentHooks(agentSource);
|
|
15536
|
+
for (const hookId of agentHooks.hooks) {
|
|
15537
|
+
await this.analyzeHook(hookId, agentsDir, analysis, false, `agent:${agentName}`);
|
|
15538
|
+
}
|
|
15539
|
+
for (const hookId of agentHooks.parentHooks) {
|
|
15540
|
+
await this.analyzeHook(hookId, agentsDir, analysis, true, `agent:${agentName}`);
|
|
15541
|
+
}
|
|
15188
15542
|
if (agentPrompts.sideA) {
|
|
15189
15543
|
analysis.primaryPrompt = agentPrompts.sideA;
|
|
15190
15544
|
await this.analyzePrompt(agentPrompts.sideA, agentsDir, analysis, /* @__PURE__ */ new Set(), `agent:${agentName}`);
|
|
@@ -15387,6 +15741,9 @@ var init_packing_service = __esm({
|
|
|
15387
15741
|
}
|
|
15388
15742
|
visited.add(`prompt:${promptName}`);
|
|
15389
15743
|
const promptSource = fs4.readFileSync(promptFilePath, "utf-8");
|
|
15744
|
+
for (const hookId of await extractPromptHooks(promptSource)) {
|
|
15745
|
+
await this.analyzeHook(hookId, agentsDir, analysis, false, thisKey);
|
|
15746
|
+
}
|
|
15390
15747
|
const modelName = await extractPromptModel(promptSource);
|
|
15391
15748
|
if (modelName) {
|
|
15392
15749
|
await this.analyzeModel(modelName, agentsDir, analysis, visited, thisKey);
|
|
@@ -15471,6 +15828,13 @@ var init_packing_service = __esm({
|
|
|
15471
15828
|
visited.add(`agent:${agentName}`);
|
|
15472
15829
|
const agentSource = fs4.readFileSync(agentFilePath, "utf-8");
|
|
15473
15830
|
const agentPrompts = await extractAgentPrompts(agentSource);
|
|
15831
|
+
const agentHooks = await extractAgentHooks(agentSource);
|
|
15832
|
+
for (const hookId of agentHooks.hooks) {
|
|
15833
|
+
await this.analyzeHook(hookId, agentsDir, analysis, false, thisKey);
|
|
15834
|
+
}
|
|
15835
|
+
for (const hookId of agentHooks.parentHooks) {
|
|
15836
|
+
await this.analyzeHook(hookId, agentsDir, analysis, true, thisKey);
|
|
15837
|
+
}
|
|
15474
15838
|
if (agentPrompts.sideA) {
|
|
15475
15839
|
await this.analyzePrompt(agentPrompts.sideA, agentsDir, analysis, visited, thisKey);
|
|
15476
15840
|
}
|
|
@@ -15478,6 +15842,27 @@ var init_packing_service = __esm({
|
|
|
15478
15842
|
await this.analyzePrompt(agentPrompts.sideB, agentsDir, analysis, visited, thisKey);
|
|
15479
15843
|
}
|
|
15480
15844
|
}
|
|
15845
|
+
/** Add a hook referenced by an agent or prompt to the packed graph. */
|
|
15846
|
+
async analyzeHook(hookId, agentsDir, analysis, required, parentKey) {
|
|
15847
|
+
const hookFilePath = await this.findFile(path4.join(agentsDir, "hooks"), hookId);
|
|
15848
|
+
if (!hookFilePath) {
|
|
15849
|
+
const message = `Hook file not found for ID: ${hookId}`;
|
|
15850
|
+
if (required) analysis.errors.push(message);
|
|
15851
|
+
else analysis.warnings.push(message);
|
|
15852
|
+
return;
|
|
15853
|
+
}
|
|
15854
|
+
if (!analysis.constituents.hooks.some(
|
|
15855
|
+
(hook) => hook.name === hookId && hook.parentKey === parentKey
|
|
15856
|
+
)) {
|
|
15857
|
+
analysis.constituents.hooks.push({
|
|
15858
|
+
name: hookId,
|
|
15859
|
+
filePath: hookFilePath,
|
|
15860
|
+
discoveredVia: "static",
|
|
15861
|
+
sharedWith: [],
|
|
15862
|
+
parentKey
|
|
15863
|
+
});
|
|
15864
|
+
}
|
|
15865
|
+
}
|
|
15481
15866
|
/**
|
|
15482
15867
|
* Analyze a model and its fallbacks.
|
|
15483
15868
|
*/
|
|
@@ -15612,11 +15997,17 @@ var init_packing_service = __esm({
|
|
|
15612
15997
|
} = options;
|
|
15613
15998
|
const finalPackageName = packageName || packageId;
|
|
15614
15999
|
const packedAt = Date.now();
|
|
16000
|
+
const entryAgentFile = await this.findFile(
|
|
16001
|
+
path4.join(rootDir, "agents", "agents"),
|
|
16002
|
+
agentName
|
|
16003
|
+
);
|
|
16004
|
+
const entryParentHooks = entryAgentFile ? (await extractAgentHooks(fs4.readFileSync(entryAgentFile, "utf-8"))).parentHookRequirements : [];
|
|
15615
16005
|
const meta = {
|
|
15616
16006
|
packageId,
|
|
15617
16007
|
version,
|
|
15618
16008
|
entryAgents: [agentName],
|
|
15619
|
-
packedAt
|
|
16009
|
+
packedAt,
|
|
16010
|
+
...entryParentHooks.length > 0 ? { parentHooks: { [agentName]: entryParentHooks } } : {}
|
|
15620
16011
|
};
|
|
15621
16012
|
const result = {
|
|
15622
16013
|
success: false,
|
|
@@ -15725,6 +16116,7 @@ var init_packing_service = __esm({
|
|
|
15725
16116
|
agentName,
|
|
15726
16117
|
this.deduplicateConstituents(analysis).effects.map((effect) => effect.name),
|
|
15727
16118
|
this.deduplicateConstituents(analysis).threadEndpoints.map((endpoint) => endpoint.name),
|
|
16119
|
+
meta.parentHooks,
|
|
15728
16120
|
externalDeps,
|
|
15729
16121
|
rootDir,
|
|
15730
16122
|
license,
|
|
@@ -16116,7 +16508,7 @@ var init_packing_service = __esm({
|
|
|
16116
16508
|
/**
|
|
16117
16509
|
* Generate the package.json file with dependencies.
|
|
16118
16510
|
*/
|
|
16119
|
-
generatePackageJson(packageName, version, agentName, effects, threadEndpoints, externalDeps, rootDir, license, licenseOwner) {
|
|
16511
|
+
generatePackageJson(packageName, version, agentName, effects, threadEndpoints, parentHooks, externalDeps, rootDir, license, licenseOwner) {
|
|
16120
16512
|
const dependencies = {
|
|
16121
16513
|
"@standardagents/spec": this.resolvePackageVersion("@standardagents/spec", rootDir)
|
|
16122
16514
|
};
|
|
@@ -16138,6 +16530,7 @@ var init_packing_service = __esm({
|
|
|
16138
16530
|
keywords: ["standardagent"],
|
|
16139
16531
|
standardagent: {
|
|
16140
16532
|
entryAgents: [agentName],
|
|
16533
|
+
...parentHooks ? { parentHooks } : {},
|
|
16141
16534
|
...effects.length > 0 ? { effects } : {},
|
|
16142
16535
|
...threadEndpoints.length > 0 ? { threadEndpoints } : {}
|
|
16143
16536
|
},
|
|
@@ -16433,6 +16826,22 @@ ${license || "See LICENSE file"}
|
|
|
16433
16826
|
};
|
|
16434
16827
|
}
|
|
16435
16828
|
});
|
|
16829
|
+
function validParentHooks(value) {
|
|
16830
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
16831
|
+
return Object.values(value).every((requirements) => {
|
|
16832
|
+
if (!Array.isArray(requirements)) return false;
|
|
16833
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16834
|
+
return requirements.every((requirement) => {
|
|
16835
|
+
if (typeof requirement !== "object" || requirement === null) return false;
|
|
16836
|
+
const item = requirement;
|
|
16837
|
+
if (typeof item.hook !== "string" || !item.hook.trim() || typeof item.reason !== "string" || !item.reason.trim() || item.stage !== void 0 && item.stage !== "before_parent" && item.stage !== "after_parent" || seen.has(item.hook)) {
|
|
16838
|
+
return false;
|
|
16839
|
+
}
|
|
16840
|
+
seen.add(item.hook);
|
|
16841
|
+
return true;
|
|
16842
|
+
});
|
|
16843
|
+
});
|
|
16844
|
+
}
|
|
16436
16845
|
var PackageDiscoveryService;
|
|
16437
16846
|
var init_discovery = __esm({
|
|
16438
16847
|
"src/packing/discovery.ts"() {
|
|
@@ -16531,6 +16940,7 @@ var init_discovery = __esm({
|
|
|
16531
16940
|
}
|
|
16532
16941
|
const effects = Array.isArray(pkgJson.standardagent.effects) && pkgJson.standardagent.effects.every((effectName) => typeof effectName === "string") ? pkgJson.standardagent.effects : void 0;
|
|
16533
16942
|
const threadEndpoints = Array.isArray(pkgJson.standardagent.threadEndpoints) && pkgJson.standardagent.threadEndpoints.every((endpoint) => typeof endpoint === "string") ? pkgJson.standardagent.threadEndpoints : void 0;
|
|
16943
|
+
const parentHooks = validParentHooks(pkgJson.standardagent.parentHooks) ? pkgJson.standardagent.parentHooks : void 0;
|
|
16534
16944
|
return {
|
|
16535
16945
|
packageId: pkgJson.name || pkgName,
|
|
16536
16946
|
version: pkgJson.version || "0.0.0",
|
|
@@ -16539,6 +16949,7 @@ var init_discovery = __esm({
|
|
|
16539
16949
|
entryAgents: pkgJson.standardagent.entryAgents,
|
|
16540
16950
|
...effects ? { effects } : {},
|
|
16541
16951
|
...threadEndpoints ? { threadEndpoints } : {},
|
|
16952
|
+
...parentHooks ? { parentHooks } : {},
|
|
16542
16953
|
description: pkgJson.description
|
|
16543
16954
|
};
|
|
16544
16955
|
} catch (error) {
|
|
@@ -16600,6 +17011,7 @@ var init_discovery = __esm({
|
|
|
16600
17011
|
}
|
|
16601
17012
|
const effects = Array.isArray(pkgJson.standardagent.effects) && pkgJson.standardagent.effects.every((effectName) => typeof effectName === "string") ? pkgJson.standardagent.effects : void 0;
|
|
16602
17013
|
const threadEndpoints = Array.isArray(pkgJson.standardagent.threadEndpoints) && pkgJson.standardagent.threadEndpoints.every((endpoint) => typeof endpoint === "string") ? pkgJson.standardagent.threadEndpoints : void 0;
|
|
17014
|
+
const parentHooks = validParentHooks(pkgJson.standardagent.parentHooks) ? pkgJson.standardagent.parentHooks : void 0;
|
|
16603
17015
|
return {
|
|
16604
17016
|
packageId: pkgJson.name || dirName,
|
|
16605
17017
|
version: pkgJson.version || "0.0.0",
|
|
@@ -16608,6 +17020,7 @@ var init_discovery = __esm({
|
|
|
16608
17020
|
entryAgents: pkgJson.standardagent.entryAgents,
|
|
16609
17021
|
...effects ? { effects } : {},
|
|
16610
17022
|
...threadEndpoints ? { threadEndpoints } : {},
|
|
17023
|
+
...parentHooks ? { parentHooks } : {},
|
|
16611
17024
|
description: pkgJson.description
|
|
16612
17025
|
};
|
|
16613
17026
|
} catch (error) {
|
|
@@ -16636,7 +17049,8 @@ var init_discovery = __esm({
|
|
|
16636
17049
|
const hasValidEntryAgents = Array.isArray(f.entryAgents) && f.entryAgents.length > 0 && f.entryAgents.every((e) => typeof e === "string");
|
|
16637
17050
|
const hasValidEffects = f.effects === void 0 || Array.isArray(f.effects) && f.effects.every((effectName) => typeof effectName === "string");
|
|
16638
17051
|
const hasValidThreadEndpoints = f.threadEndpoints === void 0 || Array.isArray(f.threadEndpoints) && f.threadEndpoints.every((endpoint) => typeof endpoint === "string");
|
|
16639
|
-
|
|
17052
|
+
const hasValidParentHooks = f.parentHooks === void 0 || validParentHooks(f.parentHooks);
|
|
17053
|
+
return hasValidEntryAgents && hasValidEffects && hasValidThreadEndpoints && hasValidParentHooks;
|
|
16640
17054
|
}
|
|
16641
17055
|
/**
|
|
16642
17056
|
* Get a package by ID.
|
|
@@ -67935,8 +68349,10 @@ var agents_get_default = defineController2(async ({ agents, agentNames, registry
|
|
|
67935
68349
|
title: definition.title || definition.name,
|
|
67936
68350
|
type: definition.type || "ai_human",
|
|
67937
68351
|
description: definition.description || null,
|
|
68352
|
+
tool_description: definition.toolDescription || null,
|
|
67938
68353
|
icon: definition.icon || null,
|
|
67939
68354
|
primary: definition.primary !== false,
|
|
68355
|
+
parentHooks: definition.parentHooks || [],
|
|
67940
68356
|
...includeAuthoringDetails ? {
|
|
67941
68357
|
default_prompt: definition.sideA?.prompt || "",
|
|
67942
68358
|
default_model: "",
|
|
@@ -67972,8 +68388,10 @@ var agents_get_default = defineController2(async ({ agents, agentNames, registry
|
|
|
67972
68388
|
title: definition.title || definition.name,
|
|
67973
68389
|
type: definition.type || "ai_human",
|
|
67974
68390
|
description: definition.description || null,
|
|
68391
|
+
tool_description: definition.toolDescription || null,
|
|
67975
68392
|
icon: definition.icon || null,
|
|
67976
68393
|
primary: definition.primary !== false,
|
|
68394
|
+
parentHooks: definition.parentHooks || [],
|
|
67977
68395
|
...includeAuthoringDetails ? {
|
|
67978
68396
|
default_prompt: definition.sideA?.prompt || "",
|
|
67979
68397
|
default_model: "",
|
|
@@ -68481,7 +68899,7 @@ var config_get_default = defineController2(async ({ config, env: env2, req }) =>
|
|
|
68481
68899
|
});
|
|
68482
68900
|
|
|
68483
68901
|
// src/version.ts
|
|
68484
|
-
var BUILDER_VERSION = "0.
|
|
68902
|
+
var BUILDER_VERSION = "0.40.1".length > 0 ? "0.40.1" : "dev";
|
|
68485
68903
|
|
|
68486
68904
|
// src/api/diagnostics.get.ts
|
|
68487
68905
|
init_LLMRequest();
|
|
@@ -69854,8 +70272,10 @@ migrations.reduce(
|
|
|
69854
70272
|
);
|
|
69855
70273
|
|
|
69856
70274
|
// src/durable-objects/DurableAgentBuilder.ts
|
|
70275
|
+
init_resolver();
|
|
69857
70276
|
init_types();
|
|
69858
70277
|
init_scope();
|
|
70278
|
+
init_ParentHookResolver();
|
|
69859
70279
|
var THREAD_PREVIEW_MAX_CHARS = 140;
|
|
69860
70280
|
var buildThreadPreview = (content) => {
|
|
69861
70281
|
const collapsed = content.replace(/\s+/g, " ").trim();
|
|
@@ -70382,6 +70802,7 @@ var name_get_default = defineController2(async ({ params, agents, prompts, promp
|
|
|
70382
70802
|
expose_as_tool: definition.exposeAsTool || false,
|
|
70383
70803
|
primary: definition.primary !== false,
|
|
70384
70804
|
tool_description: definition.toolDescription || null,
|
|
70805
|
+
parent_hooks: definition.parentHooks || [],
|
|
70385
70806
|
env: agentEnv,
|
|
70386
70807
|
tenvs: agentEnv,
|
|
70387
70808
|
// deprecated alias
|
|
@@ -75862,6 +76283,10 @@ var stream_default3 = defineController2(async (context) => {
|
|
|
75862
76283
|
|
|
75863
76284
|
// src/api/auth/device/[code]/_approval.ts
|
|
75864
76285
|
var CONFIRMATION_TTL_SECONDS = 5 * 60;
|
|
76286
|
+
var BUILT_IN_DEVICE_APPROVAL_BRAND = {
|
|
76287
|
+
name: "Standard Agents",
|
|
76288
|
+
description: "Connect a new device to your account."
|
|
76289
|
+
};
|
|
75865
76290
|
function escapeHtml(value) {
|
|
75866
76291
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
75867
76292
|
}
|
|
@@ -75878,18 +76303,85 @@ function page(title, body, ok) {
|
|
|
75878
76303
|
}
|
|
75879
76304
|
);
|
|
75880
76305
|
}
|
|
75881
|
-
function
|
|
75882
|
-
|
|
76306
|
+
function optionalPresentationText(value, maxLength) {
|
|
76307
|
+
return typeof value === "string" && value.trim() && value.trim().length <= maxLength ? value.trim() : void 0;
|
|
76308
|
+
}
|
|
76309
|
+
function safePresentationLogo(value, allowRelative) {
|
|
76310
|
+
const logoUrl = optionalPresentationText(value, 2048);
|
|
76311
|
+
if (!logoUrl) return void 0;
|
|
76312
|
+
if (allowRelative && logoUrl.startsWith("/") && !logoUrl.startsWith("//") && !logoUrl.includes("#") && !logoUrl.includes("\\")) {
|
|
76313
|
+
return logoUrl;
|
|
76314
|
+
}
|
|
76315
|
+
try {
|
|
76316
|
+
const parsed = new URL(logoUrl);
|
|
76317
|
+
if (parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.hash) return void 0;
|
|
76318
|
+
return parsed.toString();
|
|
76319
|
+
} catch {
|
|
76320
|
+
return void 0;
|
|
76321
|
+
}
|
|
76322
|
+
}
|
|
76323
|
+
function normalizeRuntimeBrand(value, platformShape) {
|
|
76324
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
76325
|
+
const record24 = value;
|
|
76326
|
+
const name15 = optionalPresentationText(record24.name, 100);
|
|
76327
|
+
if (!name15) return null;
|
|
76328
|
+
const description = optionalPresentationText(record24.description, 280);
|
|
76329
|
+
const logoValue = platformShape ? record24.logo_url : record24.logoUrl;
|
|
76330
|
+
const logoUrl = safePresentationLogo(logoValue, !platformShape);
|
|
76331
|
+
return {
|
|
76332
|
+
name: name15,
|
|
76333
|
+
...description ? { description } : {},
|
|
76334
|
+
...logoUrl ? { logoUrl } : {}
|
|
76335
|
+
};
|
|
76336
|
+
}
|
|
76337
|
+
async function resolveDeviceApprovalBrand(env2, config) {
|
|
76338
|
+
const configured = normalizeRuntimeBrand(config?.deviceApproval, false);
|
|
76339
|
+
const projectId = optionalPresentationText(
|
|
76340
|
+
env2.STANDARD_AGENTS_PROJECT_ID,
|
|
76341
|
+
128
|
|
76342
|
+
);
|
|
76343
|
+
if (isPlatformHosted(env2) && projectId) {
|
|
76344
|
+
try {
|
|
76345
|
+
const url = new URL("/partners/auth/brand", `${platformEndpoint(env2)}/`);
|
|
76346
|
+
url.searchParams.set("project_id", projectId);
|
|
76347
|
+
const response = await fetch(url, {
|
|
76348
|
+
headers: { Accept: "application/json" },
|
|
76349
|
+
signal: AbortSignal.timeout(1e3)
|
|
76350
|
+
});
|
|
76351
|
+
if (response.ok) {
|
|
76352
|
+
const payload = await response.json();
|
|
76353
|
+
const authoritative = normalizeRuntimeBrand(payload.instance, true);
|
|
76354
|
+
if (authoritative) return authoritative;
|
|
76355
|
+
}
|
|
76356
|
+
} catch {
|
|
76357
|
+
}
|
|
76358
|
+
}
|
|
76359
|
+
return configured ?? BUILT_IN_DEVICE_APPROVAL_BRAND;
|
|
76360
|
+
}
|
|
76361
|
+
function approvalCsp(req, brand) {
|
|
76362
|
+
let imageSource = "";
|
|
76363
|
+
if (brand.logoUrl) {
|
|
76364
|
+
const requestOrigin = new URL(req.url).origin;
|
|
76365
|
+
const logoOrigin = new URL(brand.logoUrl, requestOrigin).origin;
|
|
76366
|
+
imageSource = `; img-src ${logoOrigin === requestOrigin ? "'self'" : logoOrigin}`;
|
|
76367
|
+
}
|
|
76368
|
+
return `default-src 'none'; style-src 'unsafe-inline'; form-action 'self'; base-uri 'none'; frame-ancestors 'none'${imageSource}`;
|
|
76369
|
+
}
|
|
76370
|
+
function confirmationPage(req, confirmationToken, handoff, brand, identity) {
|
|
75883
76371
|
const handoffInput = handoff ? `<input type="hidden" name="handoff" value="${escapeHtml(handoff)}">` : "";
|
|
75884
|
-
const
|
|
75885
|
-
const
|
|
76372
|
+
const logo = brand.logoUrl ? `<img class="logo" src="${escapeHtml(brand.logoUrl)}" alt="">` : `<span class="logo-fallback" aria-hidden="true">${escapeHtml(brand.name.slice(0, 1).toUpperCase())}</span>`;
|
|
76373
|
+
const description = brand.description ? `<p class="description">${escapeHtml(brand.description)}</p>` : "";
|
|
76374
|
+
const secondaryIdentity = identity.displayEmail && identity.displayEmail !== identity.displayName ? `<span>${escapeHtml(identity.displayEmail)}</span>` : "";
|
|
76375
|
+
const html = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="referrer" content="no-referrer"><title>Connect device \xB7 ${escapeHtml(brand.name)}</title><style>
|
|
76376
|
+
:root{color-scheme:light dark;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;background:#f6f7f9;color:#15171a}*{box-sizing:border-box}body{margin:0;min-height:100vh;display:grid;place-items:center;padding:28px;background:radial-gradient(circle at 50% 0,rgba(71,194,174,.12),transparent 38%),linear-gradient(#fbfcfd,#f2f4f6)}main{width:min(100%,480px)}.card{background:rgba(255,255,255,.92);border:1px solid #dfe3e8;border-radius:20px;padding:34px;box-shadow:0 24px 70px rgba(20,27,38,.12),0 2px 8px rgba(20,27,38,.06)}.brand{display:flex;align-items:center;gap:12px;margin-bottom:28px}.logo,.logo-fallback{width:38px;height:38px;border-radius:10px;display:grid;place-items:center;object-fit:contain}.logo-fallback{background:#171b21;color:#fff;font-weight:750}.brand strong{font-size:17px;letter-spacing:-.01em}h1{font-size:29px;line-height:1.18;letter-spacing:-.035em;margin:0 0 12px}p{margin:0;color:#5b6470;line-height:1.58}.description{margin-bottom:20px}.request{margin-top:18px}.identity{display:flex;align-items:center;gap:12px;margin-top:24px;padding:14px;border-radius:12px;background:#f2f4f6;border:1px solid #e3e6ea}.avatar{width:34px;height:34px;border-radius:50%;display:grid;place-items:center;background:#dfe4e8;color:#313841;font-weight:700}.identity-text{min-width:0;display:flex;flex-direction:column}.identity-label{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:#737d89}.identity strong,.identity span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.identity span{font-size:13px;color:#68727e}form{display:grid;gap:10px;margin-top:26px}button{appearance:none;border-radius:11px;padding:12px 16px;font:inherit;font-weight:700;cursor:pointer}.connect{border:1px solid #15191d;background:#15191d;color:#fff}.deny{border:1px solid transparent;background:transparent;color:#68727e}.deny:hover{background:#f1f3f5;color:#252a30}.disclosure{text-align:center;font-size:12px;color:#8a939d;margin:16px 0 0}@media(prefers-color-scheme:dark){:root{background:#090b0e;color:#f2f5f7}body{background:radial-gradient(circle at 50% 0,rgba(68,198,177,.12),transparent 38%),#090b0e}.card{background:rgba(17,20,25,.94);border-color:#292e36;box-shadow:0 28px 80px rgba(0,0,0,.42)}p{color:#a9b1bc}.identity{background:#191d23;border-color:#292f38}.avatar{background:#2b323b;color:#eef2f5}.identity-label,.identity span{color:#929ca8}.connect{background:#62d4c2;border-color:#62d4c2;color:#07110f}.deny{color:#9aa4af}.deny:hover{background:#1d2229;color:#e4e8ec}.disclosure{color:#747e8a}}
|
|
76377
|
+
</style></head><body><main><section class="card"><div class="brand">${logo}<strong>${escapeHtml(brand.name)}</strong></div><h1>Connect ${escapeHtml(brand.name)}?</h1>${description}<p class="request">A new device wants to connect to your account. Only continue if you started this sign-in.</p><div class="identity"><div class="avatar" aria-hidden="true">${escapeHtml(identity.displayName.slice(0, 1).toUpperCase())}</div><div class="identity-text"><span class="identity-label">Signed in as</span><strong>${escapeHtml(identity.displayName)}</strong>${secondaryIdentity}</div></div><form method="post" action=""><input type="hidden" name="confirmation_token" value="${escapeHtml(confirmationToken)}">${handoffInput}<button class="connect" type="submit" name="decision" value="approve">Connect device</button><button class="deny" type="submit" name="decision" value="deny">Not me</button></form></section><p class="disclosure">Authentication secured by Standard Agents</p></main></body></html>`;
|
|
75886
76378
|
return new Response(html, {
|
|
75887
76379
|
headers: {
|
|
75888
76380
|
"Content-Type": "text/html; charset=utf-8",
|
|
75889
76381
|
"Cache-Control": "no-store",
|
|
75890
76382
|
"Referrer-Policy": "no-referrer",
|
|
75891
76383
|
"X-Content-Type-Options": "nosniff",
|
|
75892
|
-
"Content-Security-Policy":
|
|
76384
|
+
"Content-Security-Policy": approvalCsp(req, brand)
|
|
75893
76385
|
}
|
|
75894
76386
|
});
|
|
75895
76387
|
}
|
|
@@ -75916,7 +76408,7 @@ async function resolveDeviceApprovalIdentity(req, env2) {
|
|
|
75916
76408
|
if (!payload || !payload.platform_user_id || !payload.role || !payload.jti || !projectOk) {
|
|
75917
76409
|
return outcome(env2, false, "signin_failed", {
|
|
75918
76410
|
title: "Sign in failed",
|
|
75919
|
-
body: "This sign-in link is invalid or has expired. Start again from your
|
|
76411
|
+
body: "This sign-in link is invalid or has expired. Start again from your device."
|
|
75920
76412
|
});
|
|
75921
76413
|
}
|
|
75922
76414
|
const platformProfile = {
|
|
@@ -75931,6 +76423,8 @@ async function resolveDeviceApprovalIdentity(req, env2) {
|
|
|
75931
76423
|
return {
|
|
75932
76424
|
confirmationSubject: `platform:${payload.platform_user_id}`,
|
|
75933
76425
|
handoff,
|
|
76426
|
+
displayName: payload.display_name?.trim() || payload.username?.trim() || payload.email?.trim() || "Your account",
|
|
76427
|
+
displayEmail: payload.email?.trim() || null,
|
|
75934
76428
|
platformProfile,
|
|
75935
76429
|
platformHandoff: {
|
|
75936
76430
|
jti: payload.jti,
|
|
@@ -75962,6 +76456,8 @@ async function resolveDeviceApprovalIdentity(req, env2) {
|
|
|
75962
76456
|
return {
|
|
75963
76457
|
confirmationSubject: `user:${authResult.user.id}`,
|
|
75964
76458
|
handoff: null,
|
|
76459
|
+
displayName: authResult.user.display_name?.trim() || authResult.user.username?.trim() || authResult.user.email?.trim() || "Your account",
|
|
76460
|
+
displayEmail: authResult.user.email?.trim() || null,
|
|
75965
76461
|
localUserId: authResult.user.id
|
|
75966
76462
|
};
|
|
75967
76463
|
}
|
|
@@ -76020,7 +76516,7 @@ function isSameOriginApprovalPost(req) {
|
|
|
76020
76516
|
}
|
|
76021
76517
|
|
|
76022
76518
|
// src/api/auth/device/[code]/approve.get.ts
|
|
76023
|
-
var approve_get_default = defineController2(async ({ req, env: env2, params }) => {
|
|
76519
|
+
var approve_get_default = defineController2(async ({ req, env: env2, params, config }) => {
|
|
76024
76520
|
const code = params.code;
|
|
76025
76521
|
if (!code) {
|
|
76026
76522
|
return outcome(env2, false, "invalid_link", {
|
|
@@ -76041,7 +76537,8 @@ var approve_get_default = defineController2(async ({ req, env: env2, params }) =
|
|
|
76041
76537
|
body: "This instance cannot create a secure device confirmation. Contact its administrator."
|
|
76042
76538
|
});
|
|
76043
76539
|
}
|
|
76044
|
-
|
|
76540
|
+
const brand = await resolveDeviceApprovalBrand(env2, config);
|
|
76541
|
+
return confirmationPage(req, confirmationToken, identity.handoff, brand, identity);
|
|
76045
76542
|
});
|
|
76046
76543
|
|
|
76047
76544
|
// src/api/auth/device/[code]/approve.post.ts
|
|
@@ -76058,6 +76555,10 @@ var approve_post_default = defineController2(async ({ req, env: env2, params })
|
|
|
76058
76555
|
}
|
|
76059
76556
|
const form = await req.clone().formData().catch(() => null);
|
|
76060
76557
|
const confirmationToken = form?.get("confirmation_token")?.toString() ?? "";
|
|
76558
|
+
const decision = form?.get("decision")?.toString() || "approve";
|
|
76559
|
+
if (decision !== "approve" && decision !== "deny") {
|
|
76560
|
+
return Response.json({ error: "Invalid device confirmation decision" }, { status: 400 });
|
|
76561
|
+
}
|
|
76061
76562
|
if (!confirmationToken) {
|
|
76062
76563
|
return Response.json({ error: "Device confirmation token required" }, { status: 403 });
|
|
76063
76564
|
}
|
|
@@ -76074,31 +76575,45 @@ var approve_post_default = defineController2(async ({ req, env: env2, params })
|
|
|
76074
76575
|
if (!await consumeDeviceApprovalHandoff(env2, identity)) {
|
|
76075
76576
|
return outcome(env2, false, "signin_failed", {
|
|
76076
76577
|
title: "Sign in failed",
|
|
76077
|
-
body: "This sign-in link was already used or has expired. Start again from your
|
|
76578
|
+
body: "This sign-in link was already used or has expired. Start again from your device."
|
|
76078
76579
|
});
|
|
76079
76580
|
}
|
|
76080
|
-
const userId = await materializeDeviceApprovalUser(env2, identity);
|
|
76081
|
-
const token = generateApiKey();
|
|
76082
76581
|
const agentBuilderId = env2.AGENT_BUILDER.idFromName("singleton");
|
|
76083
76582
|
const agentBuilder = env2.AGENT_BUILDER.get(agentBuilderId);
|
|
76583
|
+
const codeHash = await hashToken(code);
|
|
76584
|
+
if (decision === "deny") {
|
|
76585
|
+
const denied = await agentBuilder.denyDeviceLogin(codeHash);
|
|
76586
|
+
if (!denied) {
|
|
76587
|
+
return outcome(env2, false, "expired", {
|
|
76588
|
+
title: "Link expired",
|
|
76589
|
+
body: "This device sign-in has expired or was already decided. Start again from your device."
|
|
76590
|
+
});
|
|
76591
|
+
}
|
|
76592
|
+
return outcome(env2, false, "denied", {
|
|
76593
|
+
title: "Connection denied",
|
|
76594
|
+
body: "The device was not connected. You can close this window."
|
|
76595
|
+
});
|
|
76596
|
+
}
|
|
76597
|
+
const userId = await materializeDeviceApprovalUser(env2, identity);
|
|
76598
|
+
const token = generateApiKey();
|
|
76084
76599
|
const ok = await agentBuilder.approveDeviceLogin({
|
|
76085
|
-
code_hash:
|
|
76600
|
+
code_hash: codeHash,
|
|
76086
76601
|
user_id: userId,
|
|
76087
76602
|
token,
|
|
76088
76603
|
token_hash: await hashToken(token),
|
|
76089
76604
|
key_prefix: token.slice(0, 12),
|
|
76090
76605
|
last_five: token.slice(-5),
|
|
76091
|
-
key_name: "
|
|
76606
|
+
key_name: "Device login"
|
|
76092
76607
|
});
|
|
76093
76608
|
if (!ok) {
|
|
76094
76609
|
return outcome(env2, false, "expired", {
|
|
76095
76610
|
title: "Link expired",
|
|
76096
|
-
body: "This device
|
|
76611
|
+
body: "This device sign-in has expired or was already decided. Start again from your device."
|
|
76097
76612
|
});
|
|
76098
76613
|
}
|
|
76099
76614
|
return outcome(env2, true, "done", {
|
|
76100
76615
|
title: "You're connected",
|
|
76101
|
-
body: "
|
|
76616
|
+
body: "The device is now connected. Return to the app that started this sign-in."
|
|
76102
76617
|
});
|
|
76103
76618
|
});
|
|
76104
76619
|
|